Compare commits

...

264 Commits

Author SHA1 Message Date
John Preston
df9ec4b466 Alpha version 1.2.20.
- Emoji and text replacements are done while you type the message.
- Revert emoji and text replacements by pressing backspace.
- Disable emoji replacements or suggestions in Settings.
- Some critical bug fixes.
2018-05-13 21:25:31 +03:00
John Preston
4f9507ed97 Fix build for Xcode 9.3.1 and OS X 10.6-10.7. 2018-05-13 21:12:44 +03:00
John Preston
f761b6aa9e Backport critical bugfix from '4f959b6b30' commit to Qt patch. 2018-05-13 20:35:40 +03:00
John Preston
168a7ce2e5 Add "Suggest emoji replacements" checkbox.
Also emoji suggestions insert an instant emoji replacement.
2018-05-13 18:56:08 +03:00
John Preston
4b763a76df Instant in-field emoji and text replaces.
Fixes #4410. Fixes #522.
2018-05-13 18:14:02 +03:00
John Preston
8764da787b Don't logout on some server-side problems. 2018-05-13 12:19:34 +03:00
John Preston
7d8ba15252 Allow to report messages in supergroups. 2018-05-10 17:15:16 +03:00
John Preston
96c0c30f7c Fix possible crash. 2018-05-10 17:15:04 +03:00
John Preston
bb6ab5314c Fix recent stickers saving and possible crash.
Regression was introduced in 97c15865a5.
2018-05-10 15:03:02 +03:00
John Preston
e3c6abfc3d Fix possible crash in reply returns. 2018-05-10 14:56:36 +03:00
John Preston
5c5bccae0b Fix proxy icon on retina and on theme changes.
Fixes #4668.
2018-05-10 13:34:06 +03:00
John Preston
296e009808 Fix proxy icon doubling.
Fixes #4666.
2018-05-10 13:24:52 +03:00
John Preston
4d84781a65 Display connecting state in history top bar. 2018-05-10 13:16:21 +03:00
John Preston
710b9bf454 Fix build for MSVC 15.7.
Fixes #4661. Fixes #4667.
2018-05-10 11:13:13 +03:00
John Preston
0f54315495 Alpha version 1.2.19.
- Enable proxy for calls in Settings.
- Bug fixes and other minor improvements.
2018-05-08 21:09:45 +03:00
John Preston
c3fc91a6fc Fix couple of possible crashes. 2018-05-08 21:06:56 +03:00
John Preston
d2048f3c25 New connecting status design. 2018-05-08 20:31:33 +03:00
John Preston
cc2c13d018 Fix build with TDESKTOP_DISABLE_AUTOUPDATE.
Fixes #4655.
2018-05-07 00:34:58 +03:00
John Preston
48c1576d7f Add 'Use proxy for calls' option. 2018-05-07 00:29:53 +03:00
John Preston
d2fa8ef0b0 Alpha version 1.2.18: Fix OS X old build. 2018-05-05 22:30:42 +03:00
John Preston
97b576f446 Alpha version 1.2.18.
- Improve working through proxy servers.
- Bug fixes and other minor improvements.
2018-05-05 22:07:05 +03:00
John Preston
257dfa6b3f Improve phone rules checking. 2018-05-05 21:55:39 +03:00
John Preston
678d2a58c5 Improve proxy row design. 2018-05-05 21:55:39 +03:00
John Preston
e0431d270b Allow cdn requests through mtproto proxy. 2018-05-05 21:55:39 +03:00
John Preston
7797e5a3b7 Improve proxies box design. 2018-05-05 21:55:39 +03:00
John Preston
d15b0cdb08 Improve infinite radial animation. 2018-05-05 21:55:39 +03:00
John Preston
1af2769209 Closed beta 1.2.17.4: Fix option lookup. 2018-05-05 21:55:39 +03:00
John Preston
e6906b84f3 Closed beta 1.2.17.3: Fix layout. 2018-05-05 21:55:39 +03:00
John Preston
ca0f6c7ded Closed beta 1.2.17.3. 2018-05-05 21:55:39 +03:00
John Preston
f9ff676e57 Improve proxies box design and progress animation. 2018-05-05 21:55:38 +03:00
John Preston
db7041f2dc Send different dns requests for simple config. 2018-05-05 21:55:38 +03:00
John Preston
ad1f089802 Read autoupdate prefix from config. 2018-05-05 21:55:38 +03:00
John Preston
62c812858e Improve config re-requesting. 2018-05-05 21:55:38 +03:00
John Preston
4bf66cb6e9 Better special config implementation. 2018-05-05 21:55:38 +03:00
John Preston
95fee543ec Try all available endpoints from config. 2018-05-05 21:55:38 +03:00
John Preston
df4daca15b Display connecting/online proxy state. 2018-05-05 21:55:38 +03:00
John Preston
f794d8dbd8 Check proxy availability in ProxiesBox. 2018-05-05 21:55:38 +03:00
John Preston
9935a36c3d Create and edit proxy box. 2018-05-05 21:55:38 +03:00
John Preston
a7c77682d7 Apply, delete and restore proxies in the box. 2018-05-05 21:55:38 +03:00
John Preston
8bbea976ea Display proxies list in a box. 2018-05-05 21:55:38 +03:00
John Preston
900d1ddb36 Support multiple proxies in local storage. 2018-05-05 21:55:38 +03:00
John Preston
8e99135f37 Support tg://proxy links. 2018-05-05 21:55:37 +03:00
John Preston
dc9483e07a Fix possible deadlock.
Some unknown code (like getSession) was called while holding
_requestsByDcLock mutex which could lead to a deadlock.

Now all access points to _requestsByDc are simple.
2018-05-05 21:55:37 +03:00
John Preston
48e913bf2c Use static version map for autoupdates. 2018-05-05 21:55:37 +03:00
John Preston
993cb987a6 Improve autoupdate code, move it from Application. 2018-05-05 21:55:37 +03:00
John Preston
65f968ec1b Update API scheme to layer 78. 2018-05-05 21:55:37 +03:00
John Preston
93f6d4b6e7 Support many config endpoints for one dc+params. 2018-05-05 21:55:37 +03:00
John Preston
7482025c10 Support work with different dcs on a single IP. 2018-05-05 21:55:37 +03:00
John Preston
909acb25fd Requesting config if can't connect. 2018-05-05 21:55:37 +03:00
John Preston
4a9db99082 Use application level proxy settings. 2018-05-05 21:55:37 +03:00
John Zimmermann
a2606c4fc4 fix libressl-2.7 compat (#4633) 2018-04-28 21:57:02 +03:00
Max Razumov
647c609bf8 Update supported version of Ubuntu (#4612) 2018-04-28 21:55:15 +03:00
John Preston
cf98025177 Use exact tagged version of OpenAL.
I hope if fixes #4531.
2018-04-18 22:10:21 +04:00
John Preston
e0f20e9f82 Version 1.2.17: Add changelog entry. 2018-04-08 21:34:33 +04:00
John Preston
597a5c9d75 Version 1.2.17: Fix undefined behaviour on exit.
Core::Launcher didn't have virtual destructor it required.
2018-04-08 21:32:48 +04:00
John Preston
d055908f4f Version 1.2.16: Improve release build scripts. 2018-04-08 18:23:12 +04:00
John Preston
f3eac6b259 Version 1.2.16: Fix text processing crash in OS X 10.6. 2018-04-08 18:21:40 +04:00
John Preston
87d6081408 Version 1.2.16: Fix build in Xcode 9.3. 2018-04-07 12:47:08 +04:00
John Preston
dd53bd1c55 Version 1.2.16.
- Bug fixes and other minor improvements.
2018-04-07 12:20:46 +04:00
Kirsan
3ff033cdf3 Fix for https://github.com/telegramdesktop/tdesktop/issues/4544
(cherry picked from commit d99c757d44d7c31fbb0eb290f273ad4d2d464255)
2018-04-07 12:13:52 +04:00
John Preston
c1c3b6a7e5 Disable emoji suggestions for :-D/:-P 2018-04-07 11:51:17 +04:00
John Preston
64d5a6acd5 Fix game scores display. 2018-04-07 11:41:48 +04:00
John Preston
e5b2e0a6b5 Fix memory clearing from photos/documents. 2018-04-07 11:01:32 +04:00
John Preston
9895b45293 Fix calls supported layer arguments. 2018-04-07 11:00:43 +04:00
John Preston
811fc43b63 Fix Qt text processing crash.
Fixes #4551.
2018-03-30 18:18:35 +04:00
John Preston
9dcfa3ad6e Version 1.2.15.
- Bug fixes and other minor improvements.
2018-03-26 02:02:58 +04:00
John Preston
67bda19458 Fix inline bot messages with previews. 2018-03-26 02:01:13 +04:00
John Preston
6c38919c3d Scroll history to down when sharing contact. 2018-03-26 01:47:05 +04:00
John Preston
ce9445287c Extend huge local cache map crash annotations. 2018-03-26 00:56:41 +04:00
John Preston
d4bd8862bd Fix switching between stickers pan and panel.
Fixes #4537.
2018-03-26 00:54:02 +04:00
John Preston
6904e023d3 Increment dropdown emoji selection in recent list.
Fixes #4539.
2018-03-26 00:28:23 +04:00
John Preston
91a7a77bb0 Fix case-insensitive emoji suggestions.
Fixes #4528, fixes #4511, fixes #4535.
2018-03-26 00:18:14 +04:00
John Preston
d9306e3e30 Fix parent link refresh for GIF webpage preview.
Fixes #4534.
2018-03-26 00:18:14 +04:00
John Preston
efdd3df129 Fix working with webpage preview GIFs.
Fixes #4533.
2018-03-26 00:18:14 +04:00
John Preston
63098d3c7d Work better with 'unlimited' config time limits. 2018-03-26 00:18:14 +04:00
Vasilii Babich
aa5781b550 Update some details in Xcode build instructions. 2018-03-25 19:29:38 +04:00
John Preston
d6e1862c08 Fix crash in AdminLog view with deleted delegates. 2018-03-22 02:27:14 +04:00
John Preston
9aa2831fef Version 1.2.14.
- Discover new stickers.
Type one emoji to see suggestions from popular sticker sets.
Suggestions from your installed sticker sets will come first.
- Search for Stickers. Click on the new search icon
to access your sticker sets or find new ones.
- Quick Reply. Double click near a message for a quick reply.
2018-03-21 18:05:45 +04:00
John Preston
70eb29c1a9 Alpha version 1.2.13.
- Bug fixes and other minor improvements.
2018-03-21 13:46:32 +04:00
John Preston
13e07b1623 Add some debug information. 2018-03-21 13:46:22 +04:00
John Preston
27ce1f8d44 Show something inside an 'empty' message. 2018-03-20 18:51:51 +04:00
John Preston
38c20fc3c2 Return one old way for requesting special config. 2018-03-20 18:21:36 +04:00
John Preston
4a32b00068 Setting for cloud stickers suggestions. 2018-03-20 01:09:03 +04:00
John Preston
3406f88fdc Single place for joining channels, in ApiWrap. 2018-03-20 01:09:03 +04:00
Marco Trevisan
c96cb37680 Travis flags update (#4506)
* travis: don't build alsoft tools, examples and tests

* travis: don't try to build with mir client support
2018-03-16 17:39:29 +03:00
John Preston
0d415837a0 Destroy old info button in top bar widget.
Fixes #4503.
2018-03-15 18:22:55 +03:00
John Preston
9dc48522d8 Fix multi-forward notification layout (long name). 2018-03-15 03:12:00 +03:00
John Preston
31b82a5d92 Show audio file performer-title in dialogs list. 2018-03-15 03:12:00 +03:00
John Preston
87ab4d9dd1 Improve local search in sticker sets.
- Don't index special sticker sets, like "Favorite stickers".
- Show "Not found." if no local results and waiting for server-side.
2018-03-15 03:11:59 +03:00
John Preston
b6e7625016 Improve case-insensitive emoji suggestions. 2018-03-15 03:11:59 +03:00
Sven-Hendrik Haase
c5e6bfce95 Fix wrong uname flag used
This is required because uname -p actually returns "unknown" for some hardware. The uname help documents this by stating that -p is non-portable. The -m flag is the one to use.
2018-03-14 15:01:26 +03:00
John Preston
7a849b2899 Fix crash on album parts being deleted. 2018-03-13 13:54:24 +03:00
John Preston
999fa39d7c Fix shared links layout for webpage previews.
Fixes #4489.
2018-03-13 13:29:56 +03:00
John Preston
7de15ce5cf Fix inline bots with photos. 2018-03-13 13:29:42 +03:00
John Preston
f792b0052f Refresh caption Text after media is being sent.
Fixes #4488.
2018-03-13 13:19:06 +03:00
John Preston
57d0b1d215 Show error when joining a full group. 2018-03-12 10:55:30 +03:00
John Preston
7691654cb8 Alpha version 1.2.12.
- Bug fixes and other minor improvements.
2018-03-12 00:00:08 +03:00
John Preston
c76e4b6b3c Fix: cancel empty reply by Escape. 2018-03-11 23:58:14 +03:00
John Preston
bda39cc6f6 Cancel empty reply by Escape. 2018-03-11 23:48:18 +03:00
John Preston
060cdfea86 Cancel reply when setting a forwarding draft. 2018-03-11 23:42:03 +03:00
John Preston
b1cc7b25ba Add group/channel info limit in EditPeerInfoBox. 2018-03-11 23:22:43 +03:00
John Preston
1e0fe70dc3 Focus correct widget in intro steps.
The old way some random shown widget could've been focused.
2018-03-11 22:55:28 +03:00
John Preston
8ed167c5fa Change domain fronting url and host header. 2018-03-11 22:55:28 +03:00
John Preston
dabf8414be Remove old debug information. 2018-03-11 22:21:17 +03:00
John Preston
a0eb64428e Use new config fields for revoke settings. 2018-03-11 22:21:17 +03:00
Patrick Eigensatz
dd1beb1d91 Let emoji suggestions be case insensitive
Closes #3985
2018-03-11 22:01:18 +03:00
John Preston
bb35d71fdc Attempt to fix access to a deleted item view. 2018-03-10 15:47:19 +03:00
John Preston
42a7e86e51 Alpha version 1.2.11.
- Bug fixes and other minor improvements.
2018-03-10 00:56:36 +03:00
John Preston
2f3540dadc Fix sending an album after cancel of one media. 2018-03-10 00:55:59 +03:00
John Preston
eb00641dfa Mark autoplayed voice/video messages as read. 2018-03-10 00:55:58 +03:00
John Preston
bfe7bf2c11 Paste image to SendFilesBox even if it has an url.
Fixes #4483.
2018-03-10 00:55:58 +03:00
Marco Trevisan (Treviño)
e88c575d4a linux: use $HOME to determine actual user path
As it could be different in confined environments.
2018-03-10 00:55:24 +03:00
Marco Trevisan (Treviño)
0de9c62675 linux-desktop-environment: detect Ubuntu properly enabling features
In Ubuntu (running in GNOME) we support AppIndicator and
Unity counters still.
2018-03-10 00:52:06 +03:00
Sean
9dc3847dbe Fix Typo 2018-03-10 00:50:05 +03:00
Marco Trevisan
9dc03c4f0f Linux ARM compile fixes (#4399)
This fixes errors when compiling in ARM
2018-03-09 23:48:47 +03:00
John Preston
def21367a3 Allow to reply by double click on the timestamp. 2018-03-09 21:22:31 +03:00
John Preston
33fe1b6389 Show no results message in share box search. 2018-03-09 21:22:31 +03:00
John Preston
76cb5677b2 Fix webpage edit display in channel admin log. 2018-03-09 21:22:31 +03:00
John Preston
8c3b7f6417 Ignore second tray icon click in short time.
Fixes #4479.
2018-03-09 21:22:31 +03:00
John Preston
e6c0f0f774 Up arrow always edits last available message.
Fixes #4480.
2018-03-09 21:22:31 +03:00
John Preston
6bd5301828 Fix crash when accessing a deleted item view. 2018-03-09 21:22:31 +03:00
John
73c0c4507a fix build against libressl 2018-03-09 21:12:34 +03:00
John Preston
506b0806d6 Fix build instructions for Linux. 2018-03-09 01:55:18 +03:00
John Preston
054459d327 Alpha version 1.2.10.
- Bug fixes and other minor improvements.
2018-03-09 00:26:58 +03:00
John Preston
66ac4d6150 No fast reply and double click reply if selecting.
Also fix messages selection glitch.
2018-03-09 00:21:27 +03:00
John Preston
ab8e7897cc No search for peers when searching by a hashtag. 2018-03-08 17:14:26 +03:00
John Preston
2b9133be90 Don't remove field focus on empty text selection.
Fixes #4467.
2018-03-08 16:03:59 +03:00
John Preston
56fece6216 Move from req_pq to req_pq_multi in protocol impl. 2018-03-08 15:55:05 +03:00
John Preston
d381836f01 Don't add separate icon for faved pack.
Also update stickers search icons.
2018-03-08 15:54:55 +03:00
John Preston
c6efb588dc Fix crash in digit-only hashtag skipping. 2018-03-08 15:02:34 +03:00
John Preston
5404dfef08 Search sticker sets locally by short name. 2018-03-08 14:37:01 +03:00
John Preston
cba12980f9 Display correct amount of stickers in search. 2018-03-08 14:12:30 +03:00
John Preston
61700577d0 Fix possible crash with invalidated views. 2018-03-08 13:47:31 +03:00
John Preston
321f5d879d Fix crash in faving stickers.
Don't fill dates in any sets except CloudRecentSetId.
Otherwise some assertions will be violated later.
2018-03-08 12:57:05 +03:00
John Preston
f98fdeab3f Alpha version 1.2.9.
- Quick Reply. Double click near a message for a quick reply.
- Search for Stickers. Click on the new search icon to access
your sticker sets or find new ones.
2018-03-08 01:45:46 +03:00
John Preston
90179188b9 Improve sticker by emoji ordering.
First display recent by send/install date, then trending, then other.
2018-03-08 00:26:35 +03:00
John Preston
ccef155f7a Receive and track recent sticker usage date. 2018-03-07 20:43:26 +03:00
John Preston
f0a95032a5 Show cloud stickers by emoji. 2018-03-07 16:53:12 +03:00
John Preston
c3ff5f2603 Limit amount of displayed recent stickers. 2018-03-07 15:04:05 +03:00
John Preston
ee182ea684 API scheme downgraded to layer 76. 2018-03-06 20:48:24 +03:00
John Preston
7f73cc3085 Fix file media with views counter layout. 2018-03-06 19:14:39 +03:00
John Preston
dcf70b2847 Add ".download" for .lnk and .scf file names.
This is a workaround for some windows shell vulnerabilities.

See http://www.defensecode.com/whitepapers/
Stealing-Windows-Credentials-Using-Google-Chrome.pdf
2018-03-06 19:04:47 +03:00
John Preston
cb5ba7edda Use a separate lang key for sticker pack remove. 2018-03-06 18:41:52 +03:00
John Preston
7940ef24ab Disallow hashtags of digits only. 2018-03-06 18:29:45 +03:00
John Preston
0f901b3728 Update API and use WebDocument for inline bots. 2018-03-06 16:49:44 +03:00
John Preston
09aba596ac Open t.me/iv links in browser. 2018-03-04 15:52:00 +03:00
John Preston
b930ac7bf9 Don't add unread mentions in channels. 2018-03-03 16:09:31 +03:00
John Preston
7f1bc4635a Update libtgvoip. 2018-03-03 16:01:22 +03:00
John Preston
d4253d2025 Fix reply previews display. 2018-03-03 15:55:53 +03:00
John Preston
b007fcb537 Add sticker sets search. 2018-03-03 14:21:32 +03:00
John Preston
e6dd7d7684 Fix crash in item view refresh. 2018-03-01 20:17:39 +03:00
John Preston
128663d95b Reply by double clicking a message. 2018-02-28 15:07:15 +03:00
John Preston
ef8b6d1a3d Process currency amounts before display. 2018-02-28 15:06:57 +03:00
John Preston
b4baebc230 Fix mediaview download icon in night mode. 2018-02-24 16:38:51 +03:00
John Preston
b4581a7bbf Closed beta 1.2.8.11. 2018-02-24 02:47:33 +03:00
John Preston
a285dca39e Apply webpage media from sent message via bot. 2018-02-24 02:46:35 +03:00
John Preston
00aa6d5ac3 Allow monospace block to end on ellipsis. 2018-02-22 21:16:01 +03:00
John Preston
027db285bc Add Info::Channels section + feed channels search. 2018-02-22 20:38:00 +03:00
John Preston
c3c9ba7e51 Add feed icons. 2018-02-22 20:37:49 +03:00
John Preston
a1be63f890 Jump to date by date click in feed. 2018-02-22 15:35:46 +03:00
John Preston
f066f3f139 Enable jump to date in feed. 2018-02-22 00:17:36 +03:00
John Preston
e17dcbb8eb Closed beta 1.2.8.10: API updated to layer 77. 2018-02-21 16:56:43 +03:00
John Preston
1ae22c8606 Fix assertion violation when no feed. 2018-02-21 16:38:56 +03:00
John Preston
d5569487a4 Closed beta 1.2.8.9. 2018-02-20 20:55:20 +03:00
John Preston
336e691dbc Add unread counter from feed to common counter. 2018-02-20 20:53:55 +03:00
John Preston
17a4d19beb Add a create feed channels list box. 2018-02-20 19:56:41 +03:00
John Preston
74aa1ad71e Ungroup all feed channels from context menu. 2018-02-18 17:00:14 +03:00
John Preston
f8c2f339a0 Create changelogs after data in AuthSession. 2018-02-18 16:26:28 +03:00
John Preston
1dd66184a1 Fix assertion violation on hashtag click. 2018-02-18 16:23:30 +03:00
John Preston
ddab8c1473 Fix fast share button hover area. 2018-02-18 16:22:58 +03:00
John Preston
49d2c97ceb Closed beta 1.2.8.8. 2018-02-16 21:00:19 +03:00
John Preston
351a423337 Highlight found messages in feed. 2018-02-16 20:59:35 +03:00
John Preston
07528be1e6 Support search in feed + scroll to search result. 2018-02-16 19:45:58 +03:00
John Preston
bc171f625a Remove some more symbols from filenames. 2018-02-15 15:34:38 +03:00
John Preston
0f775e1e66 Support feeds search display in dialogs list. 2018-02-14 23:18:21 +03:00
John Preston
98fb874b29 Closed beta 1.2.8.7. 2018-02-13 19:11:32 +03:00
John Preston
cfd5c2a650 Add feed notifications edit box. 2018-02-13 19:11:00 +03:00
John Preston
22a5b7faf6 Fix GIF playback glitch after loading. 2018-02-13 12:48:42 +03:00
John Preston
fe262701c0 Add notification toggle in feed channels. 2018-02-12 18:52:55 +03:00
John Preston
e1f71d3919 Closed beta 1.2.8.6. 2018-02-10 01:15:16 +03:00
John Preston
906cb95e67 Channels list in feed info with leave channel. 2018-02-10 01:14:26 +03:00
John Preston
f23c23f696 Closed beta 1.2.8.5. 2018-02-08 12:20:55 +03:00
John Preston
99c686e3e1 Display feed channels list in feed info. 2018-02-08 12:20:55 +03:00
John Preston
a144e35f84 Add content to feed info cover widget. 2018-02-08 12:20:55 +03:00
John Preston
5a5c5782a9 Replace crl::on_main to InvokeQueued in some cases.
If the event loop is reentered from the call it is unsafe to crl::on_main.
For example NSOpenPanel lags terribly if it is shown from crl::on_main.
2018-02-08 12:20:55 +03:00
John Preston
a2a5c30e60 Closed beta 1.2.8.4. 2018-02-08 12:20:55 +03:00
John Preston
3c4c466f8e Add cashtags and bot allowed service messages. 2018-02-08 12:20:55 +03:00
John Preston
6726826c17 Display empty feed placeholder. 2018-02-08 12:20:55 +03:00
John Preston
e102cb1469 Handle channelDifferenceTooLong in media and feed. 2018-02-08 12:20:54 +03:00
John Preston
11671e85da Add scroll-to-down button to Feed. 2018-02-08 12:20:54 +03:00
John Preston
b8614c60f9 Closed beta 1.2.8.3. 2018-02-08 12:20:54 +03:00
John Preston
269defa82d Fix forwarded Saved Messages layout. 2018-02-08 12:20:54 +03:00
John Preston
8bacc74d8b Request dialog list entries when needed.
Also save the original server-side int32 date in HistoryItems.
2018-02-08 12:20:54 +03:00
John Preston
0c5efb935d Read feed while scrolling. 2018-02-08 12:20:54 +03:00
John Preston
a7f67c4bc9 Better chats list entries management.
Make unread counts and last message base::optional<>.
Remove ChannelHistory.
2018-02-08 12:20:54 +03:00
John Preston
edcaccba1f Limit media count in one HistoryGroupedMedia. 2018-02-08 12:20:54 +03:00
John Preston
5ebecb4de3 Display feed userpic in single column layout. 2018-02-08 12:20:53 +03:00
John Preston
9f3048c1dc Hide service messages from feed. 2018-02-08 12:20:53 +03:00
John Preston
2586268b81 Remove HistoryJoined, use plain HistoryService. 2018-02-08 12:20:53 +03:00
John Preston
280ddb4629 Request full feed channels list before messages. 2018-02-08 12:20:53 +03:00
John Preston
20889d7003 Mark history as having pending resized items. 2018-02-08 12:20:53 +03:00
John Preston
d4f4698c69 Closed beta 1.2.8.2. 2018-02-08 12:20:53 +03:00
John Preston
adcce61b52 Fix date/unread bar display in albums. 2018-02-08 12:20:53 +03:00
John Preston
17b913fb13 Fix feed messages loading both ways. 2018-02-08 12:20:53 +03:00
John Preston
366ea1edc3 Notify about feed channels list changes. 2018-02-08 12:20:53 +03:00
John Preston
3a5a002be2 Add crash debug information. 2018-02-08 12:20:53 +03:00
John Preston
533fba8c70 Improve message context menu in feed. 2018-02-08 12:20:53 +03:00
John Preston
7435bd7fb0 Implement drag-n-drop from HistoryView::ListWidget. 2018-02-08 12:20:53 +03:00
John Preston
681b9b5ba3 Improve text selection in bubbles. 2018-02-08 12:20:53 +03:00
John Preston
600737c44f Fix copy selected items text in old and new lists. 2018-02-08 12:20:53 +03:00
John Preston
e5f3bed801 Improve drag selection in HistoryView::ListWidget. 2018-02-08 12:20:52 +03:00
John Preston
2fdc3169ce Fix / improve support for album items selection. 2018-02-08 12:20:52 +03:00
John Preston
722264f634 Add /Qspectre Visual C++ compiler option. 2018-02-08 12:20:52 +03:00
John Preston
a858ab5d0b Fix crash in DocumentData destructor.
Keep AuthSession pointer in DocumentData for loader destruction.
2018-02-08 12:20:52 +03:00
John Preston
63c1212ef1 Allow multiple items selection in HistoryView. 2018-02-08 12:20:52 +03:00
John Preston
2aa477176c Fix build for Xcode / GCC. 2018-02-08 12:20:52 +03:00
John Preston
6bb39451ea Closed beta 1.2.8.1. 2018-02-08 12:20:52 +03:00
John Preston
099a3c4642 Fix paste of image from Firefox.
It sometimes adds a strange path to empty temp file to mime data.
2018-02-08 12:20:52 +03:00
John Preston
9515520088 Update API scheme. 2018-02-08 12:20:52 +03:00
John Preston
fe1a90bd39 Move message context menu to a separate module. 2018-02-08 12:20:52 +03:00
John Preston
65df137610 Add group/ungroup action in channel peer menu. 2018-02-08 12:20:51 +03:00
John Preston
ced0c4d8f0 Move HistoryMessageDate to view elements. 2018-02-08 12:20:51 +03:00
John Preston
f3804429e4 Update GSL submodule. 2018-02-08 12:20:51 +03:00
John Preston
a47981054f Feed info profile placeholder. 2018-02-08 12:20:51 +03:00
John Preston
b9ad8bb700 Feed top bar placeholder. 2018-02-08 12:20:51 +03:00
John Preston
47ad5ea98a Display active feed state in dialogs list. 2018-02-08 12:20:51 +03:00
John Preston
840b42934b Use server-side my_results in contacts.search. 2018-02-08 12:20:51 +03:00
John Preston
4527c03c0d Use "Feed" name for chats list index and search. 2018-02-08 12:20:51 +03:00
John Preston
89941a8e83 Fix layout update notifications in Info::Media. 2018-02-08 12:20:50 +03:00
John Preston
ebd4651ac2 Manage unread bar using HistoryView::Element-s. 2018-02-08 12:20:50 +03:00
John Preston
861ab85ca1 Fix voice/video messages in chats/feed. 2018-02-08 12:20:50 +03:00
John Preston
f9154c4ed0 Fix albums layout and editing in feed. 2018-02-08 12:20:50 +03:00
John Preston
b91ebad8be Improve items resize in history and feed. 2018-02-08 12:20:50 +03:00
John Preston
e6baf8ef5b Fix layout of some media, enable GIF autoplay. 2018-02-08 12:20:50 +03:00
John Preston
d326c7e3fa Remove HistoryItemInstantiated. 2018-02-08 12:20:49 +03:00
John Preston
950126865e Handle item view refresh, fix groups. 2018-02-08 12:20:49 +03:00
John Preston
91f369a0b3 Handle view resize/repaint requests for mainView. 2018-02-08 12:20:49 +03:00
John Preston
d1a9d3992b API scheme updated to layer 76. 2018-02-08 12:20:49 +03:00
John Preston
2dd2ad5cdb Replace peerMessagesUpdated with notifications. 2018-02-08 12:20:49 +03:00
John Preston
04c8c95634 Use notify* instead of mark* in Data::Session. 2018-02-08 12:20:49 +03:00
John Preston
8a56ede187 Move all (item/view/media) maps to Data::Session. 2018-02-08 12:20:49 +03:00
John Preston
7425e80f05 Use HistoryMedia as view, add Data::Media. 2018-02-08 12:20:48 +03:00
John Preston
97a9089ebf Move draw / getState code to HistoryView::Message.
Item dimensions broken for now.
Also remove history.h from pch.
2018-02-08 12:20:48 +03:00
John Preston
bee474f6e9 Remove history_item and layout from pch.
Also move some code to separate modules.
Also create history item views by Window::Controller.
2018-02-08 12:20:47 +03:00
John Preston
4740d44159 Make HistoryView::Message a ClickHandlerHost. 2018-02-08 12:20:47 +03:00
John Preston
062b0b2165 Save item views in App::*Item() variables.
Also remove App::contextItem.
Also use owning pointers for history context menus.
2018-02-08 12:20:47 +03:00
John Preston
8060cb7426 Start HistoryView::Message class for item view. 2018-02-08 12:20:47 +03:00
John Preston
794e31505b First version of feed section view. 2018-02-08 12:20:46 +03:00
John Preston
50b120bc22 Fix glitch in single column back button click. 2018-02-08 12:20:46 +03:00
John Preston
f0b2e445f6 Prepare dialogs to open feeds. 2018-02-08 12:20:46 +03:00
John Preston
782e70b171 Support basic feed display in chats list. 2018-02-08 12:20:46 +03:00
John Preston
9d2239291d Add support for pinned feeds management. 2018-02-08 12:20:46 +03:00
John Preston
a2891807f8 Prepare dialogs to hold a history or a feed. 2018-02-08 12:20:46 +03:00
John Preston
6a9556d42c Move non-settings session data to Data::Session.
Rename AuthSessionData to AuthSessionSettings, move data away.
2018-02-08 12:20:46 +03:00
John Preston
724fe65d72 Start feeds support. 2018-02-08 12:20:45 +03:00
John Preston
46612ef128 Remove Notify::userIsContactChanged().
Replace with Notify::peerUpdatedDelayed().
2018-02-08 12:20:45 +03:00
John Preston
139ef5411a Prepare code for dialogFeed handling. 2018-02-08 12:20:45 +03:00
John Preston
ac57000437 Move contacts list loading to ApiWrap. 2018-02-08 12:20:45 +03:00
John Preston
31234cb487 API scheme updated to layer 75. 2018-02-08 12:20:45 +03:00
John Preston
05e36a064f API scheme updated to layer 74. 2018-02-08 12:20:45 +03:00
John Preston
f88cbf3d4b Fix crash in case of incorrect Text entities. 2018-02-08 12:20:45 +03:00
John Preston
7814ee0f7a Fix building crashpad for macOS. Update instructions.
Some tests were disabled by a crashpad patch because the changes to make
them work with new SDK are relatively big and no need to backport them.

Fixes #4353.
2018-02-08 11:27:50 +03:00
Alexander Nestorov
9f4e5e4603 Fix xcode build instructions (#4345) 2018-01-26 03:55:31 +03:00
Vitaliy Rudnyh
810fb45750 building-xcode.md: Add depot_tools to $PATH (#4331)
Otherwise "crashpad" would not compile.
2018-01-23 04:08:33 +03:00
449 changed files with 41691 additions and 19630 deletions

View File

@@ -486,6 +486,9 @@ buildOpenAL() {
-D CMAKE_INSTALL_PREFIX=$OPENAL_PATH \
-D CMAKE_BUILD_TYPE=Release \
-D LIBTYPE=STATIC \
-D ALSOFT_EXAMPLES=OFF \
-D ALSOFT_TESTS=OFF \
-D ALSOFT_UTILS=OFF \
..
make $MAKE_ARGS
sudo make install
@@ -608,7 +611,7 @@ buildCustomQt() {
./configure -prefix $QT_PATH -release -opensource -confirm-license -qt-zlib \
-qt-libpng -qt-libjpeg -qt-freetype -qt-harfbuzz -qt-pcre -qt-xcb \
-qt-xkbcommon-x11 -no-opengl -no-gtkstyle -static \
-nomake examples -nomake tests \
-nomake examples -nomake tests -no-mirclient \
-dbus-runtime -no-gstreamer -no-mtdev # <- Not sure about these
make $MAKE_ARGS
sudo make install

View File

@@ -15,7 +15,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* Windows XP - Windows 10 (**not** RT)
* Mac OS X 10.8 - Mac OS X 10.11
* Mac OS X 10.6 - Mac OS X 10.7 (separate build)
* Ubuntu 12.04 - Ubuntu 16.04
* Ubuntu 12.04 - Ubuntu 18.04
* Fedora 22 - Fedora 24
## Third-party

View File

@@ -0,0 +1,107 @@
diff --git a/client/capture_context_mac_test.cc b/client/capture_context_mac_test.cc
index 436ac5ad..8e14fb9c 100644
--- a/client/capture_context_mac_test.cc
+++ b/client/capture_context_mac_test.cc
@@ -34,11 +34,11 @@ namespace {
// gtest assertions.
void SanityCheckContext(const NativeCPUContext& context) {
#if defined(ARCH_CPU_X86)
- ASSERT_EQ(x86_THREAD_STATE32, context.tsh.flavor);
- ASSERT_EQ(implicit_cast<int>(x86_THREAD_STATE32_COUNT), context.tsh.count);
+ ASSERT_EQ(implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE32), implicit_cast<thread_state_flavor_t>(context.tsh.flavor));
+ ASSERT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE32_COUNT), implicit_cast<uint32_t>(context.tsh.count));
#elif defined(ARCH_CPU_X86_64)
- ASSERT_EQ(x86_THREAD_STATE64, context.tsh.flavor);
- ASSERT_EQ(implicit_cast<int>(x86_THREAD_STATE64_COUNT), context.tsh.count);
+ ASSERT_EQ(implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64), implicit_cast<thread_state_flavor_t>(context.tsh.flavor));
+ ASSERT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT), implicit_cast<uint32_t>(context.tsh.count));
#endif
#if defined(ARCH_CPU_X86_FAMILY)
diff --git a/client/simulate_crash_mac.cc b/client/simulate_crash_mac.cc
index 7e279015..27864388 100644
--- a/client/simulate_crash_mac.cc
+++ b/client/simulate_crash_mac.cc
@@ -177,12 +177,12 @@ bool DeliverException(thread_t thread,
void SimulateCrash(const NativeCPUContext& cpu_context) {
#if defined(ARCH_CPU_X86)
- DCHECK_EQ(cpu_context.tsh.flavor,
+ DCHECK_EQ(implicit_cast<thread_state_flavor_t>(cpu_context.tsh.flavor),
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE32));
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.tsh.count),
x86_THREAD_STATE32_COUNT);
#elif defined(ARCH_CPU_X86_64)
- DCHECK_EQ(cpu_context.tsh.flavor,
+ DCHECK_EQ(implicit_cast<thread_state_flavor_t>(cpu_context.tsh.flavor),
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64));
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.tsh.count),
x86_THREAD_STATE64_COUNT);
diff --git a/client/simulate_crash_mac_test.cc b/client/simulate_crash_mac_test.cc
index 87c5f845..ca813e4c 100644
--- a/client/simulate_crash_mac_test.cc
+++ b/client/simulate_crash_mac_test.cc
@@ -130,12 +130,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
reinterpret_cast<const x86_thread_state*>(old_state);
switch (state->tsh.flavor) {
case x86_THREAD_STATE32:
- EXPECT_EQ(implicit_cast<int>(x86_THREAD_STATE32_COUNT),
- state->tsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE32_COUNT),
+ implicit_cast<uint32_t>(state->tsh.count));
break;
case x86_THREAD_STATE64:
- EXPECT_EQ(implicit_cast<int>(x86_THREAD_STATE64_COUNT),
- state->tsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT),
+ implicit_cast<uint32_t>(state->tsh.count));
break;
default:
ADD_FAILURE() << "unexpected tsh.flavor " << state->tsh.flavor;
@@ -149,12 +149,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
reinterpret_cast<const x86_float_state*>(old_state);
switch (state->fsh.flavor) {
case x86_FLOAT_STATE32:
- EXPECT_EQ(implicit_cast<int>(x86_FLOAT_STATE32_COUNT),
- state->fsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_FLOAT_STATE32_COUNT),
+ implicit_cast<uint32_t>(state->fsh.count));
break;
case x86_FLOAT_STATE64:
- EXPECT_EQ(implicit_cast<int>(x86_FLOAT_STATE64_COUNT),
- state->fsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_FLOAT_STATE64_COUNT),
+ implicit_cast<uint32_t>(state->fsh.count));
break;
default:
ADD_FAILURE() << "unexpected fsh.flavor " << state->fsh.flavor;
@@ -168,12 +168,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
reinterpret_cast<const x86_debug_state*>(old_state);
switch (state->dsh.flavor) {
case x86_DEBUG_STATE32:
- EXPECT_EQ(implicit_cast<int>(x86_DEBUG_STATE32_COUNT),
- state->dsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_DEBUG_STATE32_COUNT),
+ implicit_cast<uint32_t>(state->dsh.count));
break;
case x86_DEBUG_STATE64:
- EXPECT_EQ(implicit_cast<int>(x86_DEBUG_STATE64_COUNT),
- state->dsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_DEBUG_STATE64_COUNT),
+ implicit_cast<uint32_t>(state->dsh.count));
break;
default:
ADD_FAILURE() << "unexpected dsh.flavor " << state->dsh.flavor;
diff --git a/crashpad.gyp b/crashpad.gyp
index 42fe0a26..d8af1bf1 100644
--- a/crashpad.gyp
+++ b/crashpad.gyp
@@ -25,7 +25,7 @@
'minidump/minidump.gyp:*',
'minidump/minidump_test.gyp:*',
'snapshot/snapshot.gyp:*',
- 'snapshot/snapshot_test.gyp:*',
+# 'snapshot/snapshot_test.gyp:*',
'test/test.gyp:*',
'test/test_test.gyp:*',
'tools/tools.gyp:*',

View File

@@ -1,5 +1,5 @@
diff --git a/build/crashpad.gypi b/build/crashpad.gypi
index 027c7b6..4bfdfb5 100644
index 027c7b68..4bfdfb5a 100644
--- a/build/crashpad.gypi
+++ b/build/crashpad.gypi
@@ -25,5 +25,15 @@
@@ -18,3 +18,110 @@ index 027c7b6..4bfdfb5 100644
+ ],
},
}
diff --git a/client/capture_context_mac_test.cc b/client/capture_context_mac_test.cc
index 436ac5ad..8e14fb9c 100644
--- a/client/capture_context_mac_test.cc
+++ b/client/capture_context_mac_test.cc
@@ -34,11 +34,11 @@ namespace {
// gtest assertions.
void SanityCheckContext(const NativeCPUContext& context) {
#if defined(ARCH_CPU_X86)
- ASSERT_EQ(x86_THREAD_STATE32, context.tsh.flavor);
- ASSERT_EQ(implicit_cast<int>(x86_THREAD_STATE32_COUNT), context.tsh.count);
+ ASSERT_EQ(implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE32), implicit_cast<thread_state_flavor_t>(context.tsh.flavor));
+ ASSERT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE32_COUNT), implicit_cast<uint32_t>(context.tsh.count));
#elif defined(ARCH_CPU_X86_64)
- ASSERT_EQ(x86_THREAD_STATE64, context.tsh.flavor);
- ASSERT_EQ(implicit_cast<int>(x86_THREAD_STATE64_COUNT), context.tsh.count);
+ ASSERT_EQ(implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64), implicit_cast<thread_state_flavor_t>(context.tsh.flavor));
+ ASSERT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT), implicit_cast<uint32_t>(context.tsh.count));
#endif
#if defined(ARCH_CPU_X86_FAMILY)
diff --git a/client/simulate_crash_mac.cc b/client/simulate_crash_mac.cc
index 7e279015..27864388 100644
--- a/client/simulate_crash_mac.cc
+++ b/client/simulate_crash_mac.cc
@@ -177,12 +177,12 @@ bool DeliverException(thread_t thread,
void SimulateCrash(const NativeCPUContext& cpu_context) {
#if defined(ARCH_CPU_X86)
- DCHECK_EQ(cpu_context.tsh.flavor,
+ DCHECK_EQ(implicit_cast<thread_state_flavor_t>(cpu_context.tsh.flavor),
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE32));
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.tsh.count),
x86_THREAD_STATE32_COUNT);
#elif defined(ARCH_CPU_X86_64)
- DCHECK_EQ(cpu_context.tsh.flavor,
+ DCHECK_EQ(implicit_cast<thread_state_flavor_t>(cpu_context.tsh.flavor),
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64));
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.tsh.count),
x86_THREAD_STATE64_COUNT);
diff --git a/client/simulate_crash_mac_test.cc b/client/simulate_crash_mac_test.cc
index 87c5f845..ca813e4c 100644
--- a/client/simulate_crash_mac_test.cc
+++ b/client/simulate_crash_mac_test.cc
@@ -130,12 +130,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
reinterpret_cast<const x86_thread_state*>(old_state);
switch (state->tsh.flavor) {
case x86_THREAD_STATE32:
- EXPECT_EQ(implicit_cast<int>(x86_THREAD_STATE32_COUNT),
- state->tsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE32_COUNT),
+ implicit_cast<uint32_t>(state->tsh.count));
break;
case x86_THREAD_STATE64:
- EXPECT_EQ(implicit_cast<int>(x86_THREAD_STATE64_COUNT),
- state->tsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT),
+ implicit_cast<uint32_t>(state->tsh.count));
break;
default:
ADD_FAILURE() << "unexpected tsh.flavor " << state->tsh.flavor;
@@ -149,12 +149,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
reinterpret_cast<const x86_float_state*>(old_state);
switch (state->fsh.flavor) {
case x86_FLOAT_STATE32:
- EXPECT_EQ(implicit_cast<int>(x86_FLOAT_STATE32_COUNT),
- state->fsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_FLOAT_STATE32_COUNT),
+ implicit_cast<uint32_t>(state->fsh.count));
break;
case x86_FLOAT_STATE64:
- EXPECT_EQ(implicit_cast<int>(x86_FLOAT_STATE64_COUNT),
- state->fsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_FLOAT_STATE64_COUNT),
+ implicit_cast<uint32_t>(state->fsh.count));
break;
default:
ADD_FAILURE() << "unexpected fsh.flavor " << state->fsh.flavor;
@@ -168,12 +168,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
reinterpret_cast<const x86_debug_state*>(old_state);
switch (state->dsh.flavor) {
case x86_DEBUG_STATE32:
- EXPECT_EQ(implicit_cast<int>(x86_DEBUG_STATE32_COUNT),
- state->dsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_DEBUG_STATE32_COUNT),
+ implicit_cast<uint32_t>(state->dsh.count));
break;
case x86_DEBUG_STATE64:
- EXPECT_EQ(implicit_cast<int>(x86_DEBUG_STATE64_COUNT),
- state->dsh.count);
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_DEBUG_STATE64_COUNT),
+ implicit_cast<uint32_t>(state->dsh.count));
break;
default:
ADD_FAILURE() << "unexpected dsh.flavor " << state->dsh.flavor;
diff --git a/crashpad.gyp b/crashpad.gyp
index 42fe0a26..d8af1bf1 100644
--- a/crashpad.gyp
+++ b/crashpad.gyp
@@ -25,7 +25,7 @@
'minidump/minidump.gyp:*',
'minidump/minidump_test.gyp:*',
'snapshot/snapshot.gyp:*',
- 'snapshot/snapshot_test.gyp:*',
+# 'snapshot/snapshot_test.gyp:*',
'test/test.gyp:*',
'test/test_test.gyp:*',
'tools/tools.gyp:*',

View File

@@ -1,5 +1,5 @@
diff --git a/configure b/configure
index cb8d78f..cadb3f0 100755
index cb8d78fd3cb..cadb3f0a880 100755
--- a/configure
+++ b/configure
@@ -511,7 +511,8 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then
@@ -13,7 +13,7 @@ index cb8d78f..cadb3f0 100755
echo " Xcode not set up properly. You may need to confirm the license" >&2
echo " agreement by running /usr/bin/xcodebuild without arguments." >&2
diff --git a/mkspecs/common/g++-macx.conf b/mkspecs/common/g++-macx.conf
index 086510d..c485967 100644
index 086510dd963..c485967863d 100644
--- a/mkspecs/common/g++-macx.conf
+++ b/mkspecs/common/g++-macx.conf
@@ -14,7 +14,13 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2
@@ -32,7 +32,7 @@ index 086510d..c485967 100644
QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvmgcc42
diff --git a/mkspecs/features/mac/default_pre.prf b/mkspecs/features/mac/default_pre.prf
index 0cc8cd6..ca9725b 100644
index 0cc8cd6dfdd..ca9725b7791 100644
--- a/mkspecs/features/mac/default_pre.prf
+++ b/mkspecs/features/mac/default_pre.prf
@@ -12,7 +12,9 @@ isEmpty(QMAKE_XCODE_DEVELOPER_PATH) {
@@ -47,7 +47,7 @@ index 0cc8cd6..ca9725b 100644
}
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index bb79a13..5d595bc 100644
index bb79a139b3c..5d595bc3b34 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -220,6 +220,10 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
@@ -74,7 +74,7 @@ index bb79a13..5d595bc 100644
if (ncols > 0) { // read color table
uchar rgb[4];
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
index ebff950..4300ca4 100644
index ebff9509ab2..4300ca4c0f0 100644
--- a/src/gui/painting/qpaintengine_p.h
+++ b/src/gui/painting/qpaintengine_p.h
@@ -87,8 +87,18 @@ public:
@@ -98,7 +98,7 @@ index ebff950..4300ca4 100644
// Make sure we're inside the viewport.
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 4879ae5..56cdcba 100644
index 4879ae51d7d..56cdcbaf01c 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -654,6 +654,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
@@ -175,7 +175,7 @@ index 4879ae5..56cdcba 100644
inline void resetRightBearing()
diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h
index cbe42c3..b273db7 100644
index cbe42c38444..b273db7e78c 100644
--- a/src/gui/text/qtextlayout.h
+++ b/src/gui/text/qtextlayout.h
@@ -194,6 +194,9 @@ private:
@@ -188,8 +188,21 @@ index cbe42c3..b273db7 100644
};
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 360f9722c70..f28f289ef6a 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -118,6 +118,8 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate()
{
for (int i = 0; i < channelCount; ++i) {
if (channels[i].socket) {
+ // Patch: backport critical bugfix from '4f959b6b30' commit.
+ QObject::disconnect(channels[i].socket, Q_NULLPTR, &channels[i], Q_NULLPTR);
channels[i].socket->close();
delete channels[i].socket;
}
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
index ca7afb7..25ae500 100644
index ca7afb7d1b9..25ae50008db 100644
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
@@ -256,6 +256,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
@@ -206,8 +219,22 @@ index ca7afb7..25ae500 100644
fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
fd->weight = QFont::Normal;
fd->style = QFont::StyleNormal;
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
index 6e2c8a2a9af..3cace8abcbc 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
@@ -717,7 +717,8 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metric
QFixed QCoreTextFontEngine::emSquareSize() const
{
- return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont)));
+ // Patch: Fix build for Xcode 9.3.1.
+ return QFixed(int(CTFontGetUnitsPerEm(ctfont)));
}
QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 92358ec..694fee7 100644
index 92358ecc745..694fee73507 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -213,7 +213,8 @@ static void cleanupCocoaApplicationDelegate()
@@ -244,7 +271,7 @@ index 92358ec..694fee7 100644
- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index b81b9a0..4e59e83 100644
index b81b9a0b1c2..4e59e833b1d 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -81,7 +81,7 @@ void QCocoaCursor::setPos(const QPoint &position)
@@ -256,8 +283,41 @@ index b81b9a0..4e59e83 100644
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
}
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 9850f83dea8..b2e1d3dfda7 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -649,9 +649,10 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm
// Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev)
OSStatus err = noErr;
- require_action(inContext != NULL, InvalidContext, err = paramErr);
- require_action(inBounds != NULL, InvalidBounds, err = paramErr);
- require_action(inImage != NULL, InvalidImage, err = paramErr);
+ // Patch: Fix build on latest Xcode.
+ //require_action(inContext != NULL, InvalidContext, err = paramErr);
+ //require_action(inBounds != NULL, InvalidBounds, err = paramErr);
+ //require_action(inImage != NULL, InvalidImage, err = paramErr);
CGContextSaveGState( inContext );
CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds));
@@ -660,9 +661,11 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm
CGContextDrawImage(inContext, *inBounds, inImage);
CGContextRestoreGState(inContext);
-InvalidImage:
-InvalidBounds:
-InvalidContext:
+
+// Patch: Fix build on latest Xcode.
+//InvalidImage:
+//InvalidBounds:
+//InvalidContext:
return err;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 9fd05a6..dea6072 100644
index 9fd05a65ee9..dea60720e78 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -402,14 +402,24 @@ void QCocoaIntegration::updateScreens()
@@ -288,7 +348,7 @@ index 9fd05a6..dea6072 100644
QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
index e46eaff..c62db53 100644
index e46eaff6be3..c62db534a2d 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
@@ -382,6 +382,12 @@ bool QCocoaKeyMapper::updateKeyboard()
@@ -315,7 +375,7 @@ index e46eaff..c62db53 100644
}
return ret;
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 83c960d..03ae969 100755
index 83c960d9317..03ae9696afe 100755
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -102,7 +102,10 @@ QT_USE_NAMESPACE
@@ -483,7 +543,7 @@ index 83c960d..03ae969 100755
}
@end
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 4d0458a..3357a5e 100644
index 4d0458a4aa2..3357a5ef817 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -167,7 +167,8 @@ static bool isMouseEvent(NSEvent *ev)
@@ -546,7 +606,7 @@ index 4d0458a..3357a5e 100644
[iconButton setImage:image];
[image release];
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index a18ee7f..1f91feb 100644
index a18ee7ff71d..1f91feb0ae8 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -393,7 +393,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
@@ -615,7 +675,7 @@ index a18ee7f..1f91feb 100644
}
return [super performKeyEquivalent:nsevent];
diff --git a/src/tools/qlalr/lalr.cpp b/src/tools/qlalr/lalr.cpp
index c680764..e2a7aaf 100644
index c68076477f3..e2a7aafa586 100644
--- a/src/tools/qlalr/lalr.cpp
+++ b/src/tools/qlalr/lalr.cpp
@@ -246,11 +246,13 @@ void Grammar::buildExtendedGrammar ()
@@ -655,7 +715,7 @@ index c680764..e2a7aaf 100644
continue;
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 7396808..7178aec 100644
index 7396808442e..7178aecf800 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -4722,6 +4722,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
@@ -708,7 +768,7 @@ index 7396808..7178aec 100644
|| (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
res = focusNextPrevChild(false);
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm
index 0845a5e..5735cb6 100644
index 0845a5eb02f..5735cb6b396 100644
--- a/src/widgets/styles/qmacstyle_mac.mm
+++ b/src/widgets/styles/qmacstyle_mac.mm
@@ -3667,9 +3667,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
@@ -726,7 +786,7 @@ index 0845a5e..5735cb6 100644
}
diff --git a/src/widgets/util/qsystemtrayicon_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp
index f98aeaf..00c0734 100644
index f98aeaf6782..00c0734129e 100644
--- a/src/widgets/util/qsystemtrayicon_qpa.cpp
+++ b/src/widgets/util/qsystemtrayicon_qpa.cpp
@@ -99,13 +99,18 @@ void QSystemTrayIconPrivate::updateIcon_sys()
@@ -755,7 +815,7 @@ index f98aeaf..00c0734 100644
}
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
index 75f3059..980f2be 100644
index 75f30599be4..980f2be1e93 100644
--- a/src/widgets/widgets/qwidgetlinecontrol.cpp
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
@@ -1867,7 +1867,8 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
@@ -769,7 +829,7 @@ index 75f3059..980f2be 100644
#ifndef QT_NO_COMPLETER
complete(event->key());
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
index 96438a0..b0b7206 100644
index 96438a0bdf7..b0b72064056 100644
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -1342,7 +1342,8 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)

View File

@@ -221,6 +221,19 @@ index f74d4d4229..8ad672c9fe 100644
};
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index c4cb8e65c0..45793e364f 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -110,6 +110,8 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate()
{
for (int i = 0; i < channelCount; ++i) {
if (channels[i].socket) {
+ // Patch: backport critical bugfix from '4f959b6b30' commit.
+ QObject::disconnect(channels[i].socket, Q_NULLPTR, &channels[i], Q_NULLPTR);
channels[i].socket->close();
delete channels[i].socket;
}
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 41834b21ae..8cdf4ab145 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
@@ -417,6 +430,20 @@ index 566abf2126..5b9c714ffa 100644
fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
fd->weight = QFont::Normal;
fd->style = QFont::StyleNormal;
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
index 7b459584ea..2ed2fd9b3b 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
@@ -764,7 +764,8 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gl
QFixed QCoreTextFontEngine::emSquareSize() const
{
- return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont)));
+ // Patch: Fix build for Xcode 9.3.1.
+ return QFixed(int(CTFontGetUnitsPerEm(ctfont)));
}
QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const
diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro
index 86bdd4729b..9b9c8ded08 100644
--- a/src/plugins/platforminputcontexts/compose/compose.pro

View File

@@ -215,8 +215,6 @@ emojiReplaceHeight: 56px;
emojiReplaceInnerHeight: 42px;
emojiReplacePadding: 14px;
connectingPadding: margins(5px, 5px, 5px, 5px);
dragFont: font(28px semibold);
dragSubfont: font(20px semibold);
dragColor: windowSubTextFg;

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

View File

@@ -296,6 +296,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_section_chat_settings" = "Chat Settings";
"lng_settings_replace_emojis" = "Replace emoji";
"lng_settings_suggest_emoji" = "Suggest emoji replacements";
"lng_settings_suggest_by_emoji" = "Suggest popular stickers by emoji";
"lng_settings_view_emojis" = "View list";
"lng_settings_send_enter" = "Send by Enter";
"lng_settings_send_ctrlenter" = "Send by Ctrl+Enter";
@@ -417,8 +419,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_connection_port_ph" = "Port";
"lng_connection_user_ph" = "Username";
"lng_connection_password_ph" = "Password";
"lng_connection_proxy_secret_ph" = "Secret";
"lng_connection_save" = "Save";
"lng_proxy_settings" = "Proxy settings";
"lng_proxy_use" = "Use proxy";
"lng_proxy_use_for_calls" = "Use proxy for calls";
"lng_proxy_about" = "Proxy servers may be helpful in accessing Telegram if there is no connection in a specific region.";
"lng_proxy_add" = "Add proxy";
"lng_proxy_share" = "Share";
"lng_proxy_online" = "online";
"lng_proxy_checking" = "checking";
"lng_proxy_connecting" = "connecting";
"lng_proxy_available" = "available (ping: {ping}ms)";
"lng_proxy_unavailable" = "not available";
"lng_proxy_edit" = "Edit proxy";
"lng_proxy_menu_edit" = "Edit";
"lng_proxy_menu_delete" = "Delete";
"lng_proxy_menu_restore" = "Restore";
"lng_proxy_edit_share" = "Share";
"lng_proxy_address_label" = "Socket address";
"lng_proxy_credentials_optional" = "Credentials (optional)";
"lng_proxy_credentials" = "Credentials";
"lng_proxy_description" = "Your saved proxy list will be here.";
"lng_settings_blocked_users" = "Blocked users";
"lng_settings_last_seen_privacy" = "Last seen privacy";
"lng_settings_calls_privacy" = "Phone calls privacy";
@@ -667,6 +691,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_report_title" = "Report channel";
"lng_report_group_title" = "Report group";
"lng_report_bot_title" = "Report bot";
"lng_report_message_title" = "Report message";
"lng_report_reason_spam" = "Spam";
"lng_report_reason_violence" = "Violence";
"lng_report_reason_pornography" = "Pornography";
@@ -793,6 +818,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_payment_done_for" = "You have just successfully transferred {amount} to {user} for {invoice}";
"lng_action_took_screenshot" = "{from} took a screenshot!";
"lng_action_you_took_screenshot" = "You took a screenshot!";
"lng_action_bot_allowed_from_domain" = "You allowed this bot to message you when you logged in on {domain}.";
"lng_ttl_photo_received" = "{from} sent you a self-destructing photo. Please view it on your mobile.";
"lng_ttl_photo_sent" = "You sent a self-destructing photo.";
@@ -818,6 +844,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_channel_not_accessible" = "Sorry, this channel is not accessible.";
"lng_group_not_accessible" = "Sorry, this group is not accessible.";
"lng_group_full" = "Sorry, this group is full.";
"lng_channels_too_much_public_about" = "Sorry, you have reserved too many public usernames. You can revoke the link from one of your older groups or channels.";
"lng_channels_too_much_public_revoke_confirm_group" = "Are you sure you want to revoke the link {link}?\n\nThe group «{group}» will become private.";
@@ -925,6 +952,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stickers_remove_group_set" = "Remove group sticker set?";
"lng_stickers_group_from_your" = "Choose from your stickers";
"lng_stickers_group_from_featured" = "Choose from trending stickers";
"lng_stickers_search_sets" = "Search sticker sets";
"lng_stickers_nothing_found" = "No stickers found";
"lng_stickers_remove_pack_confirm" = "Remove";
"lng_in_dlg_photo" = "Photo";
"lng_in_dlg_album" = "Album";
@@ -1024,6 +1054,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_user_action_upload_file" = "{user} is sending a file";
"lng_unread_bar#one" = "{count} unread message";
"lng_unread_bar#other" = "{count} unread messages";
"lng_unread_bar_some" = "Unread messages";
"lng_maps_point" = "Location";
"lng_save_photo" = "Save image";
@@ -1042,6 +1073,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_view_profile" = "View profile";
"lng_context_view_group" = "View group info";
"lng_context_view_channel" = "View channel info";
"lng_context_view_feed_info" = "View feed info";
"lng_context_pin_to_top" = "Pin to top";
"lng_context_unpin_from_top" = "Unpin from top";
@@ -1075,6 +1107,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_forward_msg" = "Forward Message";
"lng_context_delete_msg" = "Delete Message";
"lng_context_select_msg" = "Select Message";
"lng_context_report_msg" = "Report Message";
"lng_context_pin_msg" = "Pin Message";
"lng_context_unpin_msg" = "Unpin Message";
"lng_context_cancel_upload" = "Cancel Upload";
@@ -1415,6 +1448,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_admin_pin_messages" = "Pin messages";
"lng_admin_log_admin_add_admins" = "Add new admins";
"lng_feed_name" = "Feed";
"lng_feed_show_next" = "Show Next";
"lng_feed_group" = "Group in feed";
"lng_feed_ungroup" = "Ungroup from feed";
"lng_feed_channel_added" = "Channel added to your feed.";
"lng_feed_channel_removed" = "Channel removed from your feed.";
"lng_feed_no_messages" = "No messages in this feed yet";
"lng_feed_channels#one" = "{count} channel";
"lng_feed_channels#other" = "{count} channels";
"lng_feed_notifications" = "Feed notifications";
"lng_feed_ungroup_all" = "Ungroup all channels";
"lng_feed_sure_ungroup_all" = "Are you sure you want to ungroup all channels from this feed?";
"lng_feed_ungroup_sure" = "Ungroup";
"lng_feed_create_new" = "New feed";
"lng_feed_too_few_channels#one" = "You need at least {count} channel to create a feed.";
"lng_feed_too_few_channels#other" = "You need at least {count} channels to create a feed.";
"lng_feed_select_more_channels#one" = "Select {count} channel or more.";
"lng_feed_select_more_channels#other" = "Select {count} channels or more.";
"lng_feed_create" = "Create";
"lng_feed_edit_title" = "Edit feed";
"lng_feed_channels_not_found" = "No channels found";
"lng_info_feed_title" = "Feed Info";
"lng_info_feed_is_default" = "Group new channels";
"lng_info_feed_channels" = "Channels";
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose Default Program...";

View File

@@ -54,6 +54,7 @@ destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes;
---functions---
req_pq#60469778 nonce:int128 = ResPQ;
req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params;
@@ -106,8 +107,13 @@ new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long =
http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;
ipPort ipv4:int port:int = IpPort;
help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple;
//ipPort ipv4:int port:int = IpPort;
//help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple;
ipPort#d433ad73 ipv4:int port:int = IpPort;
ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort;
accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector<IpPort> = AccessPointRule;
help.configSimple#5a592a6c date:int expires:int rules:vector<AccessPointRule> = help.ConfigSimple;
---functions---
@@ -155,16 +161,16 @@ inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile
inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;
inputMediaEmpty#9664f57f = InputMedia;
inputMediaUploadedPhoto#2f37e231 flags:# file:InputFile caption:string stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
inputMediaPhoto#81fa373a flags:# id:InputPhoto caption:string ttl_seconds:flags.0?int = InputMedia;
inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia;
inputMediaUploadedDocument#e39621fd flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
inputMediaDocument#5acb668e flags:# id:InputDocument caption:string ttl_seconds:flags.0?int = InputMedia;
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia;
inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
inputMediaGifExternal#4843b0fd url:string q:string = InputMedia;
inputMediaPhotoExternal#922aec1 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia;
inputMediaDocumentExternal#b6f74335 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia;
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:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia;
@@ -219,7 +225,7 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = Chat;
chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
chatForbidden#7328bdb id:int title:string = Chat;
channel#450b7115 flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat;
channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat;
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull;
@@ -240,11 +246,11 @@ message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:fl
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#b5223b0f flags:# photo:flags.0?Photo caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia;
messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia;
messageMediaUnsupported#9f84f49e = MessageMedia;
messageMediaDocument#7c4414d3 flags:# document:flags.0?Document caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia;
messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia;
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
messageMediaGame#fdb19008 game:Game = MessageMedia;
@@ -270,6 +276,7 @@ messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAct
messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
messageActionScreenshotTaken#4792929b = MessageAction;
messageActionCustomAction#fae69f56 message:string = MessageAction;
messageActionBotAllowed#abe9affe domain:string = MessageAction;
dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
@@ -304,7 +311,6 @@ inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags
peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents;
peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents;
peerNotifySettingsEmpty#70a68512 = PeerNotifySettings;
peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings;
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
@@ -422,8 +428,8 @@ updateRecentStickers#9a422c20 = Update;
updateConfig#a229dd06 = Update;
updatePtsChanged#3354678f = Update;
updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update;
updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update;
updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector<Peer> = Update;
updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update;
updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector<DialogPeer> = Update;
updateBotWebhookJSON#8317c0c3 data:DataJSON = Update;
updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update;
updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update;
@@ -457,11 +463,11 @@ photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> =
photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
upload.fileCdnRedirect#ea52fe5a dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes cdn_file_hashes:Vector<CdnFileHash> = upload.File;
upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector<FileHash> = upload.File;
dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption;
dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
config#9c840964 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector<DisabledFeature> = Config;
config#eb7bb160 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
@@ -522,7 +528,7 @@ sendMessageGamePlayAction#dd6a8f48 = SendMessageAction;
sendMessageRecordRoundAction#88f27fbc = SendMessageAction;
sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction;
contacts.found#1aa1f784 results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;
contacts.found#b3134d9d my_results:Vector<Peer> results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;
inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey;
@@ -553,7 +559,7 @@ accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
documentAttributeAnimated#11b58939 = DocumentAttribute;
documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute;
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute;
documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
@@ -566,8 +572,6 @@ stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
messages.allStickersNotModified#e86602c3 = messages.AllStickers;
messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllStickers;
disabledFeature#ae636f24 feature:string description:string = DisabledFeature;
messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages;
contactLinkUnknown#5f4f9247 = ContactLink;
@@ -605,7 +609,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
@@ -642,6 +646,8 @@ messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity;
messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity;
messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity;
inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity;
messageEntityPhone#9b69e34b offset:int length:int = MessageEntity;
messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity;
inputChannelEmpty#ee8c1e86 = InputChannel;
inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
@@ -685,30 +691,30 @@ messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.
messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs;
messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs;
inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult;
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;
inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult;
inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult;
botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult;
botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult;
botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult;
messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults;
exportedMessageLink#1f486803 link:string = ExportedMessageLink;
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
@@ -752,7 +758,7 @@ messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers;
messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
messages.recentStickersNotModified#b17f890 = messages.RecentStickers;
messages.recentStickers#5ce20970 hash:int stickers:Vector<Document> = messages.RecentStickers;
messages.recentStickers#22f3afb3 hash:int packs:Vector<StickerPack> stickers:Vector<Document> dates:Vector<int> = messages.RecentStickers;
messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers;
@@ -834,6 +840,7 @@ paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string e
paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials;
webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> dc_id:int = WebDocument;
webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument;
@@ -855,7 +862,7 @@ payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_inf
inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials;
inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials;
inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials;
inputPaymentCredentialsAndroidPay#795667a6 payment_token:DataJSON = InputPaymentCredentials;
inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials;
account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword;
@@ -893,7 +900,7 @@ langPackDifference#f385c1f6 lang_code:string from_version:int version:int string
langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage;
channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true = ChannelAdminRights;
channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights;
channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights;
@@ -922,8 +929,6 @@ channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?tru
popularContact#5ce14175 client_id:long importers:int = PopularContact;
cdnFileHash#77eec38f offset:int limit:int hash:bytes = CdnFileHash;
messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers;
messages.favedStickers#f37f2f16 hash:int packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers;
@@ -935,7 +940,24 @@ recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl;
help.recentMeUrls#e0310d7 urls:Vector<RecentMeUrl> chats:Vector<Chat> users:Vector<User> = help.RecentMeUrls;
inputSingleMedia#5eaa7809 media:InputMedia random_id:long = InputSingleMedia;
inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector<MessageEntity> = InputSingleMedia;
webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization;
account.webAuthorizations#ed56c9fc authorizations:Vector<WebAuthorization> users:Vector<User> = account.WebAuthorizations;
inputMessageID#a676a322 id:int = InputMessage;
inputMessageReplyTo#bad88395 id:int = InputMessage;
inputMessagePinned#86872538 = InputMessage;
inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer;
dialogPeer#e56dbf05 peer:Peer = DialogPeer;
messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets;
messages.foundStickerSets#5108d648 hash:int sets:Vector<StickerSetCovered> = messages.FoundStickerSets;
fileHash#6242c773 offset:int limit:int hash:bytes = FileHash;
---functions---
@@ -963,8 +985,8 @@ auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentC
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
account.registerDevice#637ea878 token_type:int token:string = Bool;
account.unregisterDevice#65c55b40 token_type:int token:string = Bool;
account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool;
account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector<int> = Bool;
account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
account.resetNotifySettings#db7e1747 = Bool;
@@ -990,6 +1012,9 @@ account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings
account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode;
account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool;
account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword;
account.getWebAuthorizations#182e6d6f = account.WebAuthorizations;
account.resetWebAuthorization#2d01b9ef hash:long = Bool;
account.resetWebAuthorizations#682d2594 = Bool;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
@@ -1010,21 +1035,22 @@ contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.
contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool;
contacts.resetSaved#879537f1 = Bool;
messages.getMessages#4222fa74 id:Vector<int> = messages.Messages;
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs;
messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.search#39e9ea0 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates;
messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates;
messages.reportSpam#cf1592db peer:InputPeer = Bool;
messages.hideReportSpam#a8f1709b peer:InputPeer = Bool;
messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool;
messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
messages.editChatTitle#dc452855 chat_id:int title:string = Updates;
@@ -1032,7 +1058,6 @@ messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates;
messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates;
messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates;
messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates;
messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates;
messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat;
messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat;
@@ -1045,8 +1070,9 @@ messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long da
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages;
messages.getStickers#85cb5182 flags:# exclude_featured:flags.0?true emoticon:string hash:string = messages.Stickers;
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
messages.getWebPagePreview#25223e24 message:string = MessageMedia;
messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
messages.importChatInvite#6c50051c hash:string = Updates;
@@ -1072,7 +1098,7 @@ messages.editMessage#5d1b8dd flags:# no_webpage:flags.1?true stop_geo_live:flags
messages.editInlineBotMessage#b0e08243 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Bool;
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
messages.getPeerDialogs#2d9776b9 peers:Vector<InputPeer> = messages.PeerDialogs;
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
messages.getAllDrafts#6a3f8d65 = Updates;
messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers;
@@ -1090,8 +1116,8 @@ messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:Inpu
messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats;
messages.getAllChats#eba80ff0 except_ids:Vector<int> = messages.Chats;
messages.getWebPage#32ca8f91 url:string hash:int = WebPage;
messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool;
messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector<InputPeer> = Bool;
messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool;
messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector<InputDialogPeer> = Bool;
messages.getPinnedDialogs#e254d64e = messages.PeerDialogs;
messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = Bool;
messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool;
@@ -1101,9 +1127,10 @@ messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers;
messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory;
messages.getRecentLocations#249431e2 peer:InputPeer limit:int = messages.Messages;
messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages;
messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> = Updates;
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@@ -1119,8 +1146,9 @@ upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload
upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile;
upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile;
upload.reuploadCdnFile#1af91c09 file_token:bytes request_token:bytes = Vector<CdnFileHash>;
upload.getCdnFileHashes#f715c87b file_token:bytes offset:int = Vector<CdnFileHash>;
upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector<FileHash>;
upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector<FileHash>;
upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector<FileHash>;
help.getConfig#c4f9186b = Config;
help.getNearestDc#1fb33026 = NearestDc;
@@ -1138,7 +1166,7 @@ channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory;
channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool;
channels.getMessages#93d7b347 channel:InputChannel id:Vector<int> = messages.Messages;
channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages;
channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants;
channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
@@ -1156,7 +1184,7 @@ channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> =
channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite;
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates;
channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink;
channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates;
channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats;
@@ -1196,4 +1224,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector<string> = Vector<LangP
langpack.getDifference#b2e4d7d from_version:int = LangPackDifference;
langpack.getLanguages#800fd57d = Vector<LangPackLanguage>;
// LAYER 73
// LAYER 78

View File

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

View File

@@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,8,0
PRODUCTVERSION 1,2,8,0
FILEVERSION 1,2,20,0
PRODUCTVERSION 1,2,20,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -52,10 +52,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Desktop"
VALUE "FileVersion", "1.2.8.0"
VALUE "FileVersion", "1.2.20.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.2.8.0"
VALUE "ProductVersion", "1.2.20.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,8,0
PRODUCTVERSION 1,2,8,0
FILEVERSION 1,2,20,0
PRODUCTVERSION 1,2,20,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -43,10 +43,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Desktop Updater"
VALUE "FileVersion", "1.2.8.0"
VALUE "FileVersion", "1.2.20.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.2.8.0"
VALUE "ProductVersion", "1.2.20.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -480,7 +480,7 @@ int main(int argc, char *argv[])
return 0;
}
QString countBetaVersionSignature(quint64 version) { // duplicated in autoupdate.cpp
QString countBetaVersionSignature(quint64 version) { // duplicated in autoupdater.cpp
QByteArray cBetaPrivateKey(BetaPrivateKey);
if (cBetaPrivateKey.isEmpty()) {
cout << "Error: Trying to count beta version signature without beta private key!\n";

File diff suppressed because it is too large Load Diff

View File

@@ -9,24 +9,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <rpl/event_stream.h>
#include "base/timer.h"
#include "core/single_timer.h"
#include "mtproto/sender.h"
#include "base/flat_map.h"
#include "base/flat_set.h"
#include "core/single_timer.h"
#include "mtproto/sender.h"
#include "chat_helpers/stickers.h"
#include "data/data_messages.h"
class TaskQueue;
class AuthSession;
enum class SparseIdsLoadDirection;
struct MessageGroupId;
struct SendingAlbum;
enum class SendMediaType;
namespace Storage {
enum class SharedMediaType : char;
enum class SharedMediaType : signed char;
struct PreparedList;
} // namespace Storage
namespace Dialogs {
class Key;
} // namespace Dialogs
namespace Api {
inline const MTPVector<MTPChat> *getChatsFromMessagesChats(const MTPmessages_Chats &chats) {
@@ -37,6 +41,16 @@ inline const MTPVector<MTPChat> *getChatsFromMessagesChats(const MTPmessages_Cha
return nullptr;
}
template <typename IntRange>
inline int32 CountHash(IntRange &&range) {
uint32 acc = 0;
for (auto value : range) {
acc += (acc * 20261) + uint32(value);
}
return int32(acc & 0x7FFFFFFF);
}
} // namespace Api
class ApiWrap : private MTP::Sender, private base::Subscriber {
@@ -45,8 +59,27 @@ public:
void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0);
void savePinnedOrder();
//void toggleChannelGrouping( // #feed
// not_null<ChannelData*> channel,
// bool group,
// base::lambda<void()> callback);
//void ungroupAllFromFeed(not_null<Data::Feed*> feed);
using RequestMessageDataCallback = base::lambda<void(ChannelData*, MsgId)>;
void requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback callback);
void requestMessageData(
ChannelData *channel,
MsgId msgId,
RequestMessageDataCallback callback);
void requestContacts();
void requestDialogEntry(not_null<Data::Feed*> feed);
//void requestFeedDialogsEntries(not_null<Data::Feed*> feed);
void requestDialogEntry(not_null<History*> history);
//void applyFeedSources(const MTPDchannels_feedSources &data); // #feed
//void setFeedChannels(
// not_null<Data::Feed*> feed,
// const std::vector<not_null<ChannelData*>> &channels);
void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer);
@@ -55,6 +88,7 @@ public:
void requestBots(not_null<ChannelData*> channel);
void requestAdmins(not_null<ChannelData*> channel);
void requestParticipantsCountDelayed(not_null<ChannelData*> channel);
void requestChannelRangeDifference(not_null<History*> history);
void requestChangelog(
const QString &sinceVersion,
@@ -66,6 +100,9 @@ public:
void processFullPeer(PeerData *peer, const MTPmessages_ChatFull &result);
void processFullPeer(UserData *user, const MTPUserFull &result);
void markMediaRead(const base::flat_set<not_null<HistoryItem*>> &items);
void markMediaRead(not_null<HistoryItem*> item);
void requestSelfParticipant(ChannelData *channel);
void kickParticipant(not_null<ChatData*> chat, not_null<UserData*> user);
void kickParticipant(
@@ -75,6 +112,9 @@ public:
void unblockParticipant(
not_null<ChannelData*> channel,
not_null<UserData*> user);
void deleteAllFromUser(
not_null<ChannelData*> channel,
not_null<UserData*> from);
void requestWebPageDelayed(WebPageData *page);
void clearWebPageRequest(WebPageData *page);
@@ -82,12 +122,19 @@ public:
void scheduleStickerSetRequest(uint64 setId, uint64 access);
void requestStickerSets();
void saveStickerSets(const Stickers::Order &localOrder, const Stickers::Order &localRemoved);
void saveStickerSets(
const Stickers::Order &localOrder,
const Stickers::Order &localRemoved);
void updateStickers();
void setGroupStickerSet(not_null<ChannelData*> megagroup, const MTPInputStickerSet &set);
void requestRecentStickersForce();
void setGroupStickerSet(
not_null<ChannelData*> megagroup,
const MTPInputStickerSet &set);
std::vector<not_null<DocumentData*>> *stickersByEmoji(
not_null<EmojiPtr> emoji);
void joinChannel(ChannelData *channel);
void leaveChannel(ChannelData *channel);
void joinChannel(not_null<ChannelData*> channel);
void leaveChannel(not_null<ChannelData*> channel);
void blockUser(UserData *user);
void unblockUser(UserData *user);
@@ -112,7 +159,7 @@ public:
void applyUpdatesNoPtsCheck(const MTPUpdates &updates);
void applyUpdateNoPtsCheck(const MTPUpdate &update);
void jumpToDate(not_null<PeerData*> peer, const QDate &date);
void jumpToDate(Dialogs::Key chat, const QDate &date);
void preloadEnoughUnreadMentions(not_null<History*> history);
void checkForUnreadMentions(const base::flat_set<MsgId> &possiblyReadMentions, ChannelData *channel = nullptr);
@@ -122,7 +169,7 @@ public:
bool adminsEnabled,
base::flat_set<not_null<UserData*>> &&admins);
using SliceType = SparseIdsLoadDirection;
using SliceType = Data::LoadDirection;
void requestSharedMedia(
not_null<PeerData*> peer,
Storage::SharedMediaType type,
@@ -136,6 +183,14 @@ public:
not_null<UserData*> user,
PhotoId afterId);
//void requestFeedChannels( // #feed
// not_null<Data::Feed*> feed);
//void requestFeedMessages(
// not_null<Data::Feed*> feed,
// Data::MessagePosition messageId,
// SliceType slice);
//void saveDefaultFeedId(FeedId id, bool isDefaultFeedId);
void stickerSetInstalled(uint64 setId) {
_stickerSetInstalled.fire_copy(setId);
}
@@ -185,6 +240,9 @@ public:
void shareContact(not_null<UserData*> user, const SendOptions &options);
void readServerHistory(not_null<History*> history);
void readServerHistoryForce(not_null<History*> history);
void readFeed(
not_null<Data::Feed*> feed,
Data::MessagePosition position);
void sendVoiceMessage(
QByteArray result,
@@ -224,6 +282,12 @@ private:
using MessageDataRequests = QMap<MsgId, MessageDataRequest>;
using SharedMediaType = Storage::SharedMediaType;
struct StickersByEmoji {
std::vector<not_null<DocumentData*>> list;
QString hash;
TimeMs received = 0;
};
void updatesReceived(const MTPUpdates &updates);
void checkQuitPreventFinished();
@@ -235,8 +299,13 @@ private:
ChannelData *channel,
mtpRequestId requestId);
QVector<MTPint> collectMessageIds(const MessageDataRequests &requests);
QVector<MTPInputMessage> collectMessageIds(const MessageDataRequests &requests);
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
void historyDialogEntryApplied(not_null<History*> history);
void applyFeedDialogs(
not_null<Data::Feed*> feed,
const MTPmessages_Dialogs &dialogs);
void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req);
void gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestId req);
@@ -253,16 +322,31 @@ private:
int availableCount,
const QVector<MTPChannelParticipant> &list);
void resolveWebPages();
void gotWebPages(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req);
void gotWebPages(
ChannelData *channel,
const MTPmessages_Messages &result,
mtpRequestId req);
void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result);
PeerData *notifySettingReceived(MTPInputNotifyPeer peer, const MTPPeerNotifySettings &settings);
void channelRangeDifferenceSend(
not_null<ChannelData*> channel,
MsgRange range,
int32 pts);
void channelRangeDifferenceDone(
not_null<ChannelData*> channel,
MsgRange range,
const MTPupdates_ChannelDifference &result);
PeerData *notifySettingReceived(
MTPInputNotifyPeer peer,
const MTPPeerNotifySettings &settings);
void stickerSetDisenabled(mtpRequestId requestId);
void stickersSaveOrder();
void requestStickers(TimeId now);
void requestRecentStickers(TimeId now);
void requestRecentStickersWithHash(int32 hash);
void requestFavedStickers(TimeId now);
void requestFeaturedStickers(TimeId now);
void requestSavedGifs(TimeId now);
@@ -275,11 +359,19 @@ private:
not_null<ChannelData*> channel,
const QVector<MTPChannelParticipant> &participants);
void jumpToHistoryDate(not_null<PeerData*> peer, const QDate &date);
void jumpToFeedDate(not_null<Data::Feed*> feed, const QDate &date);
template <typename Callback>
void requestMessageAfterDate(
not_null<PeerData*> peer,
const QDate &date,
Callback &&callback);
template <typename Callback>
void requestMessageAfterDate(
not_null<Data::Feed*> feed,
const QDate &date,
Callback &&callback);
void sharedMediaDone(
not_null<PeerData*> peer,
@@ -293,6 +385,13 @@ private:
PhotoId photoId,
const MTPphotos_Photos &result);
//void feedChannelsDone(not_null<Data::Feed*> feed); // #feed
//void feedMessagesDone(
// not_null<Data::Feed*> feed,
// Data::MessagePosition messageId,
// SliceType slice,
// const MTPmessages_FeedMessages &result);
void sendSharedContact(
const QString &phone,
const QString &firstName,
@@ -308,6 +407,11 @@ private:
void applyAffectedMessages(
not_null<PeerData*> peer,
const MTPmessages_AffectedMessages &result);
void deleteAllFromUserSend(
not_null<ChannelData*> channel,
not_null<UserData*> from);
void sendMessageFail(const RPCError &error);
void uploadAlbumMedia(
not_null<HistoryItem*> item,
@@ -331,6 +435,8 @@ private:
bool silent,
uint64 randomId);
void readFeeds();
not_null<AuthSession*> _session;
MessageDataRequests _messageDataRequests;
@@ -348,7 +454,11 @@ private:
ChannelData *_channelMembersForAdd = nullptr;
mtpRequestId _channelMembersForAddRequestId = 0;
base::lambda<void(const MTPchannels_ChannelParticipants&)> _channelMembersForAddCallback;
base::lambda<void(
const MTPchannels_ChannelParticipants&)> _channelMembersForAddCallback;
base::flat_map<
not_null<ChannelData*>,
std::pair<mtpRequestId,base::lambda<void()>>> _channelGroupingRequests;
using KickRequest = std::pair<
not_null<ChannelData*>,
@@ -357,6 +467,10 @@ private:
QMap<ChannelData*, mtpRequestId> _selfParticipantRequests;
base::flat_map<
not_null<ChannelData*>,
mtpRequestId> _rangeDifferenceRequests;
QMap<WebPageData*, mtpRequestId> _webPagesPending;
base::Timer _webPagesTimer;
@@ -385,9 +499,14 @@ private:
base::Timer _featuredSetsReadTimer;
base::flat_set<uint64> _featuredSetsRead;
QMap<mtpTypeId, mtpRequestId> _privacySaveRequests;
base::flat_map<not_null<EmojiPtr>, StickersByEmoji> _stickersByEmoji;
base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests;
mtpRequestId _contactsRequestId = 0;
mtpRequestId _contactsStatusesRequestId = 0;
base::flat_set<not_null<Data::Feed*>> _dialogFeedRequests;
base::flat_set<not_null<History*>> _dialogRequests;
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;
@@ -409,6 +528,20 @@ private:
base::flat_map<not_null<UserData*>, mtpRequestId> _userPhotosRequests;
base::flat_set<not_null<Data::Feed*>> _feedChannelsGetRequests;
base::flat_map<
not_null<Data::Feed*>,
mtpRequestId> _feedChannelsSetRequests;
base::flat_set<std::tuple<
not_null<Data::Feed*>,
Data::MessagePosition,
SliceType>> _feedMessagesRequests;
base::flat_set<std::tuple<
not_null<Data::Feed*>,
Data::MessagePosition,
SliceType>> _feedMessagesRequestsPending;
mtpRequestId _saveDefaultFeedIdRequest = 0;
rpl::event_stream<SendOptions> _sendActions;
struct ReadRequest {
@@ -422,6 +555,7 @@ private:
};
base::flat_map<not_null<PeerData*>, ReadRequest> _readRequests;
base::flat_map<not_null<PeerData*>, MsgId> _readRequestsPending;
std::unique_ptr<TaskQueue> _fileLoader;
base::flat_map<uint64, std::shared_ptr<SendingAlbum>> _sendingAlbums;
@@ -429,4 +563,8 @@ private:
rpl::event_stream<uint64> _stickerSetInstalled;
base::flat_map<not_null<Data::Feed*>, TimeMs> _feedReadsDelayed;
base::flat_map<not_null<Data::Feed*>, mtpRequestId> _feedReadRequests;
base::Timer _feedReadTimer;
};

File diff suppressed because it is too large Load Diff

View File

@@ -8,27 +8,60 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "core/basic_types.h"
#include "history/history.h"
#include "history/history_item.h"
#include "layout.h"
#include "data/data_types.h"
#include "data/data_peer.h"
enum NewMessageType : char;
class Messenger;
class MainWindow;
class MainWidget;
using HistoryItemsMap = OrderedSet<HistoryItem*>;
using PhotoItems = QHash<PhotoData*, HistoryItemsMap>;
using DocumentItems = QHash<DocumentData*, HistoryItemsMap>;
using WebPageItems = QHash<WebPageData*, HistoryItemsMap>;
using GameItems = QHash<GameData*, HistoryItemsMap>;
using SharedContactItems = QHash<int32, HistoryItemsMap>;
using GifItems = QHash<Media::Clip::Reader*, HistoryItem*>;
using PhotosData = QHash<PhotoId, PhotoData*>;
using DocumentsData = QHash<DocumentId, DocumentData*>;
class LocationCoords;
struct LocationData;
class HistoryItem;
class History;
class Histories;
namespace HistoryView {
class Element;
} // namespace HistoryView
using HistoryItemsMap = base::flat_set<not_null<HistoryItem*>>;
using GifItems = QHash<Media::Clip::Reader*, HistoryItem*>;
enum RoundCorners {
SmallMaskCorners = 0x00, // for images
LargeMaskCorners,
BoxCorners,
MenuCorners,
BotKbOverCorners,
StickerCorners,
StickerSelectedCorners,
SelectedOverlaySmallCorners,
SelectedOverlayLargeCorners,
DateCorners,
DateSelectedCorners,
ForwardCorners,
MediaviewSaveCorners,
EmojiHoverCorners,
StickerHoverCorners,
BotKeyboardCorners,
PhotoSelectOverlayCorners,
Doc1Corners,
Doc2Corners,
Doc3Corners,
Doc4Corners,
InShadowCorners, // for photos without bg
InSelectedShadowCorners,
MessageInCorners, // with shadow
MessageInSelectedCorners,
MessageOutCorners,
MessageOutSelectedCorners,
RoundCornersCount
};
namespace App {
MainWindow *wnd();
@@ -62,18 +95,6 @@ namespace App {
ImagePtr image(const MTPPhotoSize &size);
PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs);
PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = nullptr);
PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = nullptr);
DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb);
DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = nullptr);
DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = nullptr);
WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert = nullptr);
WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = nullptr);
WebPageData *feedWebPage(const MTPWebPage &webpage);
WebPageData *feedWebPage(WebPageId webPageId, const QString &siteName, const TextWithEntities &content);
GameData *feedGame(const MTPDgame &game, GameData *convert = nullptr);
PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded);
inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asUser(peer(id, restriction));
@@ -119,53 +140,7 @@ namespace App {
UserData *self();
PeerData *peerByName(const QString &username);
QString peerName(const PeerData *peer, bool forDialogs = false);
PhotoData *photo(const PhotoId &photo);
PhotoData *photoSet(
const PhotoId &photo,
PhotoData *convert,
const uint64 &access,
int32 date,
const ImagePtr &thumb,
const ImagePtr &medium,
const ImagePtr &full);
DocumentData *document(const DocumentId &document);
DocumentData *documentSet(
const DocumentId &document,
DocumentData *convert,
const uint64 &access,
int32 version,
int32 date,
const QVector<MTPDocumentAttribute> &attributes,
const QString &mime,
const ImagePtr &thumb,
int32 dc,
int32 size,
const StorageImageLocation &thumbLocation);
WebPageData *webPage(const WebPageId &webPage);
WebPageData *webPageSet(
const WebPageId &webPage,
WebPageData *convert,
const QString &type,
const QString &url,
const QString &displayUrl,
const QString &siteName,
const QString &title,
const TextWithEntities &description,
PhotoData *photo,
DocumentData *document,
int duration,
const QString &author,
int pendingTill);
GameData *game(const GameId &game);
GameData *gameSet(
const GameId &game,
GameData *convert,
const uint64 &accessHash,
const QString &shortName,
const QString &title,
const QString &description,
PhotoData *photo,
DocumentData *document);
LocationData *location(const LocationCoords &coords);
void forgetMedia();
@@ -173,7 +148,6 @@ namespace App {
Histories &histories();
not_null<History*> history(const PeerId &peer);
History *historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead, int32 maxOutboxRead);
History *historyLoaded(const PeerId &peer);
HistoryItem *histItemById(ChannelId channelId, MsgId itemId);
inline not_null<History*> history(const PeerData *peer) {
@@ -189,10 +163,9 @@ namespace App {
inline HistoryItem *histItemById(const FullMsgId &msgId) {
return histItemById(msgId.channel, msgId.msg);
}
void historyRegItem(HistoryItem *item);
void historyItemDetached(HistoryItem *item);
void historyUnregItem(HistoryItem *item);
void historyUpdateDependent(HistoryItem *item);
void historyRegItem(not_null<HistoryItem*> item);
void historyUnregItem(not_null<HistoryItem*> item);
void historyUpdateDependent(not_null<HistoryItem*> item);
void historyClearMsgs();
void historyClearItems();
void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency);
@@ -205,18 +178,16 @@ namespace App {
void historyUnregSentData(uint64 randomId);
void histSentDataByItem(uint64 randomId, PeerId &peerId, QString &text);
void hoveredItem(HistoryItem *item);
HistoryItem *hoveredItem();
void pressedItem(HistoryItem *item);
HistoryItem *pressedItem();
void hoveredLinkItem(HistoryItem *item);
HistoryItem *hoveredLinkItem();
void pressedLinkItem(HistoryItem *item);
HistoryItem *pressedLinkItem();
void contextItem(HistoryItem *item);
HistoryItem *contextItem();
void mousedItem(HistoryItem *item);
HistoryItem *mousedItem();
void hoveredItem(HistoryView::Element *item);
HistoryView::Element *hoveredItem();
void pressedItem(HistoryView::Element *item);
HistoryView::Element *pressedItem();
void hoveredLinkItem(HistoryView::Element *item);
HistoryView::Element *hoveredLinkItem();
void pressedLinkItem(HistoryView::Element *item);
HistoryView::Element *pressedLinkItem();
void mousedItem(HistoryView::Element *item);
HistoryView::Element *mousedItem();
void clearMousedItems();
const style::font &monofont();
@@ -250,44 +221,10 @@ namespace App {
QImage readImage(const QString &file, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr, QByteArray *content = 0);
QPixmap pixmapFromImageInPlace(QImage &&image);
void regPhotoItem(PhotoData *data, HistoryItem *item);
void unregPhotoItem(PhotoData *data, HistoryItem *item);
const PhotoItems &photoItems();
const PhotosData &photosData();
void regDocumentItem(DocumentData *data, HistoryItem *item);
void unregDocumentItem(DocumentData *data, HistoryItem *item);
const DocumentItems &documentItems();
const DocumentsData &documentsData();
void regWebPageItem(WebPageData *data, HistoryItem *item);
void unregWebPageItem(WebPageData *data, HistoryItem *item);
const WebPageItems &webPageItems();
void regGameItem(GameData *data, HistoryItem *item);
void unregGameItem(GameData *data, HistoryItem *item);
const GameItems &gameItems();
void regSharedContactItem(int32 userId, HistoryItem *item);
void unregSharedContactItem(int32 userId, HistoryItem *item);
const SharedContactItems &sharedContactItems();
QString phoneFromSharedContact(int32 userId);
void regGifItem(Media::Clip::Reader *reader, HistoryItem *item);
void unregGifItem(Media::Clip::Reader *reader);
void stopRoundVideoPlayback();
void stopGifItems();
void regMuted(not_null<PeerData*> peer, TimeMs changeIn);
void unregMuted(not_null<PeerData*> peer);
void updateMuted();
void setProxySettings(QNetworkAccessManager &manager);
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
QNetworkProxy getHttpProxySettings();
#endif // !TDESKTOP_DISABLE_NETWORK_PROXY
void setProxySettings(QTcpSocket &socket);
void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, RectParts corners);
void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, RectParts corners);

View File

@@ -11,11 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwidget.h"
#include "mainwindow.h"
#include "storage/localstorage.h"
#include "autoupdater.h"
#include "window/notifications_manager.h"
#include "core/crash_reports.h"
#include "messenger.h"
#include "base/timer.h"
#include "core/update_checker.h"
#include "core/crash_report_window.h"
namespace {
@@ -65,7 +65,11 @@ Application::Application(
int &argc,
char **argv)
: QApplication(argc, argv)
, _launcher(launcher) {
, _launcher(launcher)
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
, _updateChecker(std::make_unique<Core::UpdateChecker>())
#endif // TDESKTOP_DISABLE_AUTOUPDATE
{
const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
char h[33] = { 0 };
hashMd5Hex(d.constData(), d.size(), h);
@@ -86,13 +90,6 @@ Application::Application(
QTimer::singleShot(0, this, SLOT(startApplication()));
connect(this, SIGNAL(aboutToQuit()), this, SLOT(closeApplication()));
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
_updateCheckTimer.create(this);
connect(_updateCheckTimer, SIGNAL(timeout()), this, SLOT(updateCheck()));
connect(this, SIGNAL(updateFailed()), this, SLOT(onUpdateFailed()));
connect(this, SIGNAL(updateReady()), this, SLOT(onUpdateReady()));
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
if (cManyInstance()) {
LOG(("Many instance allowed, starting..."));
singleInstanceChecked();
@@ -180,7 +177,7 @@ void Application::socketError(QLocalSocket::LocalSocketError e) {
#endif // !Q_OS_WINRT
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
if (!cNoStartUpdate() && checkReadyUpdate()) {
if (!cNoStartUpdate() && Core::checkReadyUpdate()) {
cSetRestartingUpdate(true);
DEBUG_LOG(("Application Info: installing update instead of starting app..."));
return App::quit();
@@ -196,6 +193,7 @@ void Application::singleInstanceChecked() {
}
Sandbox::start();
refreshGlobalProxy();
if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) {
new NotStartedWindow();
@@ -307,9 +305,29 @@ void Application::startApplication() {
void Application::createMessenger() {
Expects(!App::quitting());
_messengerInstance = std::make_unique<Messenger>(_launcher);
}
void Application::refreshGlobalProxy() {
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
const auto proxy = [&] {
if (Global::started()) {
return Global::UseProxy()
? Global::SelectedProxy()
: ProxyData();
}
return Sandbox::PreLaunchProxy();
}();
if (proxy.type == ProxyData::Type::Socks5
|| proxy.type == ProxyData::Type::Http) {
QNetworkProxy::setApplicationProxy(ToNetworkProxy(proxy));
} else {
QNetworkProxyFactory::setUseSystemConfiguration(true);
}
#endif // TDESKTOP_DISABLE_NETWORK_PROXY
}
void Application::closeApplication() {
if (App::launchState() == App::QuitProcessed) return;
App::setLaunchState(App::QuitProcessed);
@@ -328,169 +346,10 @@ void Application::closeApplication() {
_localSocket.close();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
delete _updateReply;
_updateReply = 0;
if (_updateChecker) _updateChecker->deleteLater();
_updateChecker = 0;
if (_updateThread) {
_updateThread->quit();
}
_updateThread = 0;
_updateChecker = nullptr;
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
}
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void Application::updateCheck() {
startUpdateCheck(false);
}
void Application::updateGotCurrent() {
if (!_updateReply || _updateThread) return;
cSetLastUpdateCheck(unixtime());
QRegularExpressionMatch m = QRegularExpression(qsl("^\\s*(\\d+)\\s*:\\s*([\\x21-\\x7f]+)\\s*$")).match(QString::fromLatin1(_updateReply->readAll()));
if (m.hasMatch()) {
uint64 currentVersion = m.captured(1).toULongLong();
QString url = m.captured(2);
bool betaVersion = false;
if (url.startsWith(qstr("beta_"))) {
betaVersion = true;
url = url.mid(5) + '_' + countBetaVersionSignature(currentVersion);
}
if ((!betaVersion || cBetaVersion()) && currentVersion > (betaVersion ? cBetaVersion() : uint64(AppVersion))) {
_updateThread = new QThread();
connect(_updateThread, SIGNAL(finished()), _updateThread, SLOT(deleteLater()));
_updateChecker = new UpdateChecker(_updateThread, url);
_updateThread->start();
}
}
if (_updateReply) _updateReply->deleteLater();
_updateReply = 0;
if (!_updateThread) {
QDir updates(cWorkingDir() + "tupdates");
if (updates.exists()) {
QFileInfoList list = updates.entryInfoList(QDir::Files);
for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) {
if (QRegularExpression("^(tupdate|tmacupd|tmac32upd|tlinuxupd|tlinux32upd)\\d+(_[a-z\\d]+)?$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) {
QFile(i->absoluteFilePath()).remove();
}
}
}
emit updateLatest();
}
startUpdateCheck(true);
Local::writeSettings();
}
void Application::updateFailedCurrent(QNetworkReply::NetworkError e) {
LOG(("App Error: could not get current version (update check): %1").arg(e));
if (_updateReply) _updateReply->deleteLater();
_updateReply = 0;
emit updateFailed();
startUpdateCheck(true);
}
void Application::onUpdateReady() {
if (_updateChecker) {
_updateChecker->deleteLater();
_updateChecker = nullptr;
}
_updateCheckTimer->stop();
cSetLastUpdateCheck(unixtime());
Local::writeSettings();
}
void Application::onUpdateFailed() {
if (_updateChecker) {
_updateChecker->deleteLater();
_updateChecker = 0;
if (_updateThread) _updateThread->quit();
_updateThread = 0;
}
cSetLastUpdateCheck(unixtime());
Local::writeSettings();
}
Application::UpdatingState Application::updatingState() {
if (!_updateThread) return Application::UpdatingNone;
if (!_updateChecker) return Application::UpdatingReady;
return Application::UpdatingDownload;
}
int32 Application::updatingSize() {
if (!_updateChecker) return 0;
return _updateChecker->size();
}
int32 Application::updatingReady() {
if (!_updateChecker) return 0;
return _updateChecker->ready();
}
void Application::stopUpdate() {
if (_updateReply) {
_updateReply->abort();
_updateReply->deleteLater();
_updateReply = 0;
}
if (_updateChecker) {
_updateChecker->deleteLater();
_updateChecker = 0;
if (_updateThread) _updateThread->quit();
_updateThread = 0;
}
}
void Application::startUpdateCheck(bool forceWait) {
if (!Sandbox::started()) return;
_updateCheckTimer->stop();
if (_updateThread || _updateReply || !cAutoUpdate() || cExeName().isEmpty()) return;
int32 constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart, randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart;
int32 updateInSecs = cLastUpdateCheck() + constDelay + int32(rand() % randDelay) - unixtime();
bool sendRequest = (updateInSecs <= 0 || updateInSecs > (constDelay + randDelay));
if (!sendRequest && !forceWait) {
QDir updates(cWorkingDir() + "tupdates");
if (updates.exists()) {
QFileInfoList list = updates.entryInfoList(QDir::Files);
for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) {
if (QRegularExpression("^(tupdate|tmacupd|tmac32upd|tlinuxupd|tlinux32upd)\\d+(_[a-z\\d]+)?$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) {
sendRequest = true;
}
}
}
}
if (cManyInstance() && !cDebug()) return; // only main instance is updating
if (sendRequest) {
QUrl url(cUpdateURL());
if (cBetaVersion()) {
url.setQuery(qsl("version=%1&beta=%2").arg(AppVersion).arg(cBetaVersion()));
} else if (cAlphaVersion()) {
url.setQuery(qsl("version=%1&alpha=1").arg(AppVersion));
} else {
url.setQuery(qsl("version=%1").arg(AppVersion));
}
QString u = url.toString();
QNetworkRequest checkVersion(url);
if (_updateReply) _updateReply->deleteLater();
App::setProxySettings(_updateManager);
_updateReply = _updateManager.get(checkVersion);
connect(_updateReply, SIGNAL(finished()), this, SLOT(updateGotCurrent()));
connect(_updateReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(updateFailedCurrent(QNetworkReply::NetworkError)));
emit updateChecking();
} else {
_updateCheckTimer->start((updateInSecs + 5) * 1000);
}
}
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
inline Application *application() {
return qobject_cast<Application*>(QApplication::instance());
}
@@ -542,73 +401,6 @@ void adjustSingleTimers() {
base::Timer::Adjust();
}
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void startUpdateCheck() {
if (auto a = application()) {
return a->startUpdateCheck(false);
}
}
void stopUpdate() {
if (auto a = application()) {
return a->stopUpdate();
}
}
Application::UpdatingState updatingState() {
if (auto a = application()) {
return a->updatingState();
}
return Application::UpdatingNone;
}
int32 updatingSize() {
if (auto a = application()) {
return a->updatingSize();
}
return 0;
}
int32 updatingReady() {
if (auto a = application()) {
return a->updatingReady();
}
return 0;
}
void updateChecking() {
if (auto a = application()) {
emit a->updateChecking();
}
}
void updateLatest() {
if (auto a = application()) {
emit a->updateLatest();
}
}
void updateProgress(qint64 ready, qint64 total) {
if (auto a = application()) {
emit a->updateProgress(ready, total);
}
}
void updateFailed() {
if (auto a = application()) {
emit a->updateFailed();
}
}
void updateReady() {
if (auto a = application()) {
emit a->updateReady();
}
}
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
void connect(const char *signal, QObject *object, const char *method) {
if (auto a = application()) {
a->connect(a, signal, object, method);
@@ -648,4 +440,10 @@ void launch() {
application()->createMessenger();
}
void refreshGlobalProxy() {
if (const auto instance = application()) {
instance->refreshGlobalProxy();
}
}
} // namespace Sandbox

View File

@@ -7,10 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class UpdateChecker;
namespace Core {
class Launcher;
class UpdateChecker;
} // namespace Core
class Application : public QApplication {
@@ -22,6 +21,7 @@ public:
bool event(QEvent *e) override;
void createMessenger();
void refreshGlobalProxy();
~Application();
@@ -58,46 +58,11 @@ private:
void singleInstanceChecked();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
// Autoupdating
public:
void startUpdateCheck(bool forceWait);
void stopUpdate();
enum UpdatingState {
UpdatingNone,
UpdatingDownload,
UpdatingReady,
};
UpdatingState updatingState();
int32 updatingSize();
int32 updatingReady();
signals:
void updateChecking();
void updateLatest();
void updateProgress(qint64 ready, qint64 total);
void updateReady();
void updateFailed();
public slots:
void updateCheck();
void updateGotCurrent();
void updateFailedCurrent(QNetworkReply::NetworkError e);
void onUpdateReady();
void onUpdateFailed();
private:
object_ptr<SingleTimer> _updateCheckTimer = { nullptr };
QNetworkReply *_updateReply = nullptr;
QNetworkAccessManager _updateManager;
QThread *_updateThread = nullptr;
UpdateChecker *_updateChecker = nullptr;
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
std::unique_ptr<Core::UpdateChecker> _updateChecker;
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
};
namespace Sandbox {
@@ -111,22 +76,7 @@ void execExternal(const QString &cmd);
void adjustSingleTimers();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void startUpdateCheck();
void stopUpdate();
Application::UpdatingState updatingState();
int32 updatingSize();
int32 updatingReady();
void updateChecking();
void updateLatest();
void updateProgress(qint64 ready, qint64 total);
void updateFailed();
void updateReady();
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
void refreshGlobalProxy();
void connect(const char *signal, QObject *object, const char *method);

View File

@@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/localstorage.h"
#include "storage/storage_facade.h"
#include "storage/serialize_common.h"
#include "history/history_item_components.h"
#include "data/data_session.h"
#include "window/notifications_manager.h"
#include "window/themes/window_theme.h"
#include "platform/platform_specific.h"
@@ -30,14 +30,14 @@ constexpr auto kAutoLockTimeoutLateMs = TimeMs(3000);
} // namespace
AuthSessionData::Variables::Variables()
AuthSessionSettings::Variables::Variables()
: sendFilesWay(SendFilesWay::Album)
, selectorTab(ChatHelpers::SelectorTab::Emoji)
, floatPlayerColumn(Window::Column::Second)
, floatPlayerCorner(RectPart::TopRight) {
}
QByteArray AuthSessionData::serialize() const {
QByteArray AuthSessionSettings::serialize() const {
auto size = sizeof(qint32) * 10;
for (auto i = _variables.soundOverrides.cbegin(), e = _variables.soundOverrides.cend(); i != e; ++i) {
size += Serialize::stringSize(i.key()) + Serialize::stringSize(i.value());
@@ -76,7 +76,7 @@ QByteArray AuthSessionData::serialize() const {
return result;
}
void AuthSessionData::constructFromSerialized(const QByteArray &serialized) {
void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized) {
if (serialized.isEmpty()) {
return;
}
@@ -146,7 +146,8 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) {
thirdSectionExtendedBy = value;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: Bad data for AuthSessionData::constructFromSerialized()"));
LOG(("App Error: "
"Bad data for AuthSessionSettings::constructFromSerialized()"));
return;
}
@@ -190,87 +191,7 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) {
}
}
void AuthSessionData::markItemLayoutChanged(not_null<const HistoryItem*> item) {
_itemLayoutChanged.fire_copy(item);
}
rpl::producer<not_null<const HistoryItem*>> AuthSessionData::itemLayoutChanged() const {
return _itemLayoutChanged.events();
}
void AuthSessionData::requestItemRepaint(not_null<const HistoryItem*> item) {
_itemRepaintRequest.fire_copy(item);
}
rpl::producer<not_null<const HistoryItem*>> AuthSessionData::itemRepaintRequest() const {
return _itemRepaintRequest.events();
}
void AuthSessionData::markItemRemoved(not_null<const HistoryItem*> item) {
_itemRemoved.fire_copy(item);
}
rpl::producer<not_null<const HistoryItem*>> AuthSessionData::itemRemoved() const {
return _itemRemoved.events();
}
void AuthSessionData::markHistoryUnloaded(not_null<const History*> history) {
_historyUnloaded.fire_copy(history);
}
rpl::producer<not_null<const History*>> AuthSessionData::historyUnloaded() const {
return _historyUnloaded.events();
}
void AuthSessionData::markHistoryCleared(not_null<const History*> history) {
_historyCleared.fire_copy(history);
}
rpl::producer<not_null<const History*>> AuthSessionData::historyCleared() const {
return _historyCleared.events();
}
void AuthSessionData::removeMegagroupParticipant(
not_null<ChannelData*> channel,
not_null<UserData*> user) {
_megagroupParticipantRemoved.fire({ channel, user });
}
auto AuthSessionData::megagroupParticipantRemoved() const -> rpl::producer<MegagroupParticipant> {
return _megagroupParticipantRemoved.events();
}
rpl::producer<not_null<UserData*>> AuthSessionData::megagroupParticipantRemoved(
not_null<ChannelData*> channel) const {
return megagroupParticipantRemoved(
) | rpl::filter([channel](auto updateChannel, auto user) {
return (updateChannel == channel);
}) | rpl::map([](auto updateChannel, auto user) {
return user;
});
}
void AuthSessionData::addNewMegagroupParticipant(
not_null<ChannelData*> channel,
not_null<UserData*> user) {
_megagroupParticipantAdded.fire({ channel, user });
}
auto AuthSessionData::megagroupParticipantAdded() const -> rpl::producer<MegagroupParticipant> {
return _megagroupParticipantAdded.events();
}
rpl::producer<not_null<UserData*>> AuthSessionData::megagroupParticipantAdded(
not_null<ChannelData*> channel) const {
return megagroupParticipantAdded(
) | rpl::filter([channel](auto updateChannel, auto user) {
return (updateChannel == channel);
}) | rpl::map([](auto updateChannel, auto user) {
return user;
});
}
void AuthSessionData::setTabbedSelectorSectionEnabled(bool enabled) {
void AuthSessionSettings::setTabbedSelectorSectionEnabled(bool enabled) {
_variables.tabbedSelectorSectionEnabled = enabled;
if (enabled) {
setThirdSectionInfoEnabled(false);
@@ -278,12 +199,12 @@ void AuthSessionData::setTabbedSelectorSectionEnabled(bool enabled) {
setTabbedReplacedWithInfo(false);
}
rpl::producer<bool> AuthSessionData::tabbedReplacedWithInfoValue() const {
rpl::producer<bool> AuthSessionSettings::tabbedReplacedWithInfoValue() const {
return _tabbedReplacedWithInfoValue.events_starting_with(
tabbedReplacedWithInfo());
}
void AuthSessionData::setThirdSectionInfoEnabled(bool enabled) {
void AuthSessionSettings::setThirdSectionInfoEnabled(bool enabled) {
if (_variables.thirdSectionInfoEnabled != enabled) {
_variables.thirdSectionInfoEnabled = enabled;
if (enabled) {
@@ -294,19 +215,19 @@ void AuthSessionData::setThirdSectionInfoEnabled(bool enabled) {
}
}
rpl::producer<bool> AuthSessionData::thirdSectionInfoEnabledValue() const {
rpl::producer<bool> AuthSessionSettings::thirdSectionInfoEnabledValue() const {
return _thirdSectionInfoEnabledValue.events_starting_with(
thirdSectionInfoEnabled());
}
void AuthSessionData::setTabbedReplacedWithInfo(bool enabled) {
void AuthSessionSettings::setTabbedReplacedWithInfo(bool enabled) {
if (_tabbedReplacedWithInfo != enabled) {
_tabbedReplacedWithInfo = enabled;
_tabbedReplacedWithInfoValue.fire_copy(enabled);
}
}
QString AuthSessionData::getSoundPath(const QString &key) const {
QString AuthSessionSettings::getSoundPath(const QString &key) const {
auto it = _variables.soundOverrides.constFind(key);
if (it != _variables.soundOverrides.end()) {
return it.value();
@@ -314,75 +235,30 @@ QString AuthSessionData::getSoundPath(const QString &key) const {
return qsl(":/sounds/") + key + qsl(".mp3");
}
void AuthSessionData::setDialogsWidthRatio(float64 ratio) {
void AuthSessionSettings::setDialogsWidthRatio(float64 ratio) {
_variables.dialogsWidthRatio = ratio;
}
float64 AuthSessionData::dialogsWidthRatio() const {
float64 AuthSessionSettings::dialogsWidthRatio() const {
return _variables.dialogsWidthRatio.current();
}
rpl::producer<float64> AuthSessionData::dialogsWidthRatioChanges() const {
rpl::producer<float64> AuthSessionSettings::dialogsWidthRatioChanges() const {
return _variables.dialogsWidthRatio.changes();
}
void AuthSessionData::setThirdColumnWidth(int width) {
void AuthSessionSettings::setThirdColumnWidth(int width) {
_variables.thirdColumnWidth = width;
}
int AuthSessionData::thirdColumnWidth() const {
int AuthSessionSettings::thirdColumnWidth() const {
return _variables.thirdColumnWidth.current();
}
rpl::producer<int> AuthSessionData::thirdColumnWidthChanges() const {
rpl::producer<int> AuthSessionSettings::thirdColumnWidthChanges() const {
return _variables.thirdColumnWidth.changes();
}
void AuthSessionData::markStickersUpdated() {
_stickersUpdated.fire({});
}
rpl::producer<> AuthSessionData::stickersUpdated() const {
return _stickersUpdated.events();
}
void AuthSessionData::markSavedGifsUpdated() {
_savedGifsUpdated.fire({});
}
rpl::producer<> AuthSessionData::savedGifsUpdated() const {
return _savedGifsUpdated.events();
}
HistoryItemsList AuthSessionData::idsToItems(
const MessageIdsList &ids) const {
return ranges::view::all(
ids
) | ranges::view::transform([](const FullMsgId &fullId) {
return App::histItemById(fullId);
}) | ranges::view::filter([](HistoryItem *item) {
return item != nullptr;
}) | ranges::view::transform([](HistoryItem *item) {
return not_null<HistoryItem*>(item);
}) | ranges::to_vector;
}
MessageIdsList AuthSessionData::itemsToIds(
const HistoryItemsList &items) const {
return ranges::view::all(
items
) | ranges::view::transform([](not_null<HistoryItem*> item) {
return item->fullId();
}) | ranges::to_vector;
}
MessageIdsList AuthSessionData::groupToIds(
not_null<HistoryMessageGroup*> group) const {
auto result = itemsToIds(group->others);
result.push_back(group->leader->fullId());
return result;
}
AuthSession &Auth() {
auto result = Messenger::Instance().authSession();
Assert(result != nullptr);
@@ -398,13 +274,14 @@ AuthSession::AuthSession(UserId userId)
, _uploader(std::make_unique<Storage::Uploader>())
, _storage(std::make_unique<Storage::Facade>())
, _notifications(std::make_unique<Window::Notifications::System>(this))
, _data(std::make_unique<Data::Session>(this))
, _changelogs(Core::Changelogs::Create(this)) {
Expects(_userId != 0);
_saveDataTimer.setCallback([this] {
_saveDataTimer.setCallback([=] {
Local::writeUserSettings();
});
subscribe(Messenger::Instance().passcodedChanged(), [this] {
subscribe(Messenger::Instance().passcodedChanged(), [=] {
_shouldLockAt = 0;
notifications().updateAll();
});
@@ -427,7 +304,10 @@ base::Observable<void> &AuthSession::downloaderTaskFinished() {
}
bool AuthSession::validateSelf(const MTPUser &user) {
if (user.type() != mtpc_user || !user.c_user().is_self() || user.c_user().vid.v != userId()) {
if (user.type() != mtpc_user || !user.c_user().is_self()) {
LOG(("API Error: bad self user received."));
return false;
} else if (user.c_user().vid.v != userId()) {
LOG(("Auth Error: wrong self user received."));
App::logOutDelayed();
return false;
@@ -435,8 +315,9 @@ bool AuthSession::validateSelf(const MTPUser &user) {
return true;
}
void AuthSession::saveDataDelayed(TimeMs delay) {
void AuthSession::saveSettingsDelayed(TimeMs delay) {
Expects(this == &Auth());
_saveDataTimer.callOnce(delay);
}
@@ -447,7 +328,7 @@ void AuthSession::checkAutoLock() {
auto now = getms(true);
auto shouldLockInMs = Global::AutoLock() * 1000LL;
auto idleForMs = psIdleTime();
auto notPlayingVideoForMs = now - data().lastTimeVideoPlayedAt();
auto notPlayingVideoForMs = now - settings().lastTimeVideoPlayedAt();
auto checkTimeMs = qMin(idleForMs, notPlayingVideoForMs);
if (checkTimeMs >= shouldLockInMs || (_shouldLockAt > 0 && now > _shouldLockAt + kAutoLockTimeoutLateMs)) {
Messenger::Instance().setupPasscode();

View File

@@ -11,11 +11,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <rpl/filter.h>
#include <rpl/variable.h>
#include "base/timer.h"
#include "chat_helpers/stickers.h"
class ApiWrap;
enum class SendFilesWay;
namespace Data {
class Session;
} // namespace Data
namespace Storage {
class Downloader;
class Uploader;
@@ -41,65 +44,20 @@ namespace Core {
class Changelogs;
} // namespace Core
class AuthSessionData final {
class AuthSessionSettings final {
public:
base::Variable<bool> &contactsLoaded() {
return _contactsLoaded;
}
base::Variable<bool> &allChatsLoaded() {
return _allChatsLoaded;
}
base::Observable<void> &moreChatsLoaded() {
return _moreChatsLoaded;
}
base::Observable<void> &pendingHistoryResize() {
return _pendingHistoryResize;
}
struct ItemVisibilityQuery {
not_null<HistoryItem*> item;
not_null<bool*> isVisible;
};
base::Observable<ItemVisibilityQuery> &queryItemVisibility() {
return _queryItemVisibility;
}
void markItemLayoutChanged(not_null<const HistoryItem*> item);
rpl::producer<not_null<const HistoryItem*>> itemLayoutChanged() const;
void requestItemRepaint(not_null<const HistoryItem*> item);
rpl::producer<not_null<const HistoryItem*>> itemRepaintRequest() const;
void markItemRemoved(not_null<const HistoryItem*> item);
rpl::producer<not_null<const HistoryItem*>> itemRemoved() const;
void markHistoryUnloaded(not_null<const History*> history);
rpl::producer<not_null<const History*>> historyUnloaded() const;
void markHistoryCleared(not_null<const History*> history);
rpl::producer<not_null<const History*>> historyCleared() const;
using MegagroupParticipant = std::tuple<
not_null<ChannelData*>,
not_null<UserData*>>;
void removeMegagroupParticipant(
not_null<ChannelData*> channel,
not_null<UserData*> user);
rpl::producer<MegagroupParticipant> megagroupParticipantRemoved() const;
rpl::producer<not_null<UserData*>> megagroupParticipantRemoved(
not_null<ChannelData*> channel) const;
void addNewMegagroupParticipant(
not_null<ChannelData*> channel,
not_null<UserData*> user);
rpl::producer<MegagroupParticipant> megagroupParticipantAdded() const;
rpl::producer<not_null<UserData*>> megagroupParticipantAdded(
not_null<ChannelData*> channel) const;
void moveFrom(AuthSessionData &&other) {
void moveFrom(AuthSessionSettings &&other) {
_variables = std::move(other._variables);
}
QByteArray serialize() const;
void constructFromSerialized(const QByteArray &serialized);
bool lastSeenWarningSeen() const {
return _variables.lastSeenWarningSeen;
}
void setLastSeenWarningSeen(bool lastSeenWarningSeen) {
_variables.lastSeenWarningSeen = lastSeenWarningSeen;
}
bool lastSeenWarningSeen() const {
return _variables.lastSeenWarningSeen;
}
void setSendFilesWay(SendFilesWay way) {
_variables.sendFilesWay = way;
}
@@ -176,10 +134,6 @@ public:
int thirdColumnWidth() const;
rpl::producer<int> thirdColumnWidthChanges() const;
void markStickersUpdated();
rpl::producer<> stickersUpdated() const;
void markSavedGifsUpdated();
rpl::producer<> savedGifsUpdated() const;
void setGroupStickersSectionHidden(PeerId peerId) {
_variables.groupStickersSectionHidden.insert(peerId);
}
@@ -189,79 +143,6 @@ public:
void removeGroupStickersSectionHidden(PeerId peerId) {
_variables.groupStickersSectionHidden.remove(peerId);
}
bool stickersUpdateNeeded(TimeMs now) const {
return stickersUpdateNeeded(_lastStickersUpdate, now);
}
void setLastStickersUpdate(TimeMs update) {
_lastStickersUpdate = update;
}
bool recentStickersUpdateNeeded(TimeMs now) const {
return stickersUpdateNeeded(_lastRecentStickersUpdate, now);
}
void setLastRecentStickersUpdate(TimeMs update) {
_lastRecentStickersUpdate = update;
}
bool favedStickersUpdateNeeded(TimeMs now) const {
return stickersUpdateNeeded(_lastFavedStickersUpdate, now);
}
void setLastFavedStickersUpdate(TimeMs update) {
_lastFavedStickersUpdate = update;
}
bool featuredStickersUpdateNeeded(TimeMs now) const {
return stickersUpdateNeeded(_lastFeaturedStickersUpdate, now);
}
void setLastFeaturedStickersUpdate(TimeMs update) {
_lastFeaturedStickersUpdate = update;
}
bool savedGifsUpdateNeeded(TimeMs now) const {
return stickersUpdateNeeded(_lastSavedGifsUpdate, now);
}
void setLastSavedGifsUpdate(TimeMs update) {
_lastSavedGifsUpdate = update;
}
int featuredStickerSetsUnreadCount() const {
return _featuredStickerSetsUnreadCount.current();
}
void setFeaturedStickerSetsUnreadCount(int count) {
_featuredStickerSetsUnreadCount = count;
}
rpl::producer<int> featuredStickerSetsUnreadCountValue() const {
return _featuredStickerSetsUnreadCount.value();
}
const Stickers::Sets &stickerSets() const {
return _stickerSets;
}
Stickers::Sets &stickerSetsRef() {
return _stickerSets;
}
const Stickers::Order &stickerSetsOrder() const {
return _stickerSetsOrder;
}
Stickers::Order &stickerSetsOrderRef() {
return _stickerSetsOrder;
}
const Stickers::Order &featuredStickerSetsOrder() const {
return _featuredStickerSetsOrder;
}
Stickers::Order &featuredStickerSetsOrderRef() {
return _featuredStickerSetsOrder;
}
const Stickers::Order &archivedStickerSetsOrder() const {
return _archivedStickerSetsOrder;
}
Stickers::Order &archivedStickerSetsOrderRef() {
return _archivedStickerSetsOrder;
}
const Stickers::SavedGifs &savedGifs() const {
return _savedGifs;
}
Stickers::SavedGifs &savedGifsRef() {
return _savedGifs;
}
HistoryItemsList idsToItems(const MessageIdsList &ids) const;
MessageIdsList itemsToIds(const HistoryItemsList &items) const;
MessageIdsList groupToIds(not_null<HistoryMessageGroup*> group) const;
private:
struct Variables {
@@ -288,39 +169,6 @@ private:
= kDefaultThirdColumnWidth; // per-window
};
bool stickersUpdateNeeded(TimeMs lastUpdate, TimeMs now) const {
constexpr auto kStickersUpdateTimeout = TimeMs(3600'000);
return (lastUpdate == 0)
|| (now >= lastUpdate + kStickersUpdateTimeout);
}
base::Variable<bool> _contactsLoaded = { false };
base::Variable<bool> _allChatsLoaded = { false };
base::Observable<void> _moreChatsLoaded;
base::Observable<void> _pendingHistoryResize;
base::Observable<ItemVisibilityQuery> _queryItemVisibility;
rpl::event_stream<not_null<const HistoryItem*>> _itemLayoutChanged;
rpl::event_stream<not_null<const HistoryItem*>> _itemRepaintRequest;
rpl::event_stream<not_null<const HistoryItem*>> _itemRemoved;
rpl::event_stream<not_null<const History*>> _historyUnloaded;
rpl::event_stream<not_null<const History*>> _historyCleared;
rpl::event_stream<MegagroupParticipant> _megagroupParticipantRemoved;
rpl::event_stream<MegagroupParticipant> _megagroupParticipantAdded;
rpl::event_stream<> _stickersUpdated;
rpl::event_stream<> _savedGifsUpdated;
TimeMs _lastStickersUpdate = 0;
TimeMs _lastRecentStickersUpdate = 0;
TimeMs _lastFavedStickersUpdate = 0;
TimeMs _lastFeaturedStickersUpdate = 0;
TimeMs _lastSavedGifsUpdate = 0;
rpl::variable<int> _featuredStickerSetsUnreadCount = 0;
Stickers::Sets _stickerSets;
Stickers::Order _stickerSetsOrder;
Stickers::Order _featuredStickerSetsOrder;
Stickers::Order _archivedStickerSetsOrder;
Stickers::SavedGifs _savedGifs;
rpl::event_stream<bool> _thirdSectionInfoEnabledValue;
bool _tabbedReplacedWithInfo = false;
rpl::event_stream<bool> _tabbedReplacedWithInfoValue;
@@ -334,7 +182,9 @@ private:
class AuthSession;
AuthSession &Auth();
class AuthSession final : private base::Subscriber {
class AuthSession final
: public base::has_weak_ptr
, private base::Subscriber {
public:
AuthSession(UserId userId);
@@ -368,10 +218,13 @@ public:
return *_notifications;
}
AuthSessionData &data() {
return _data;
Data::Session &data() {
return *_data;
}
void saveDataDelayed(TimeMs delay = kDefaultSaveDelay);
AuthSessionSettings &settings() {
return _settings;
}
void saveSettingsDelayed(TimeMs delay = kDefaultSaveDelay);
ApiWrap &api() {
return *_api;
@@ -393,7 +246,7 @@ private:
static constexpr auto kDefaultSaveDelay = TimeMs(1000);
const UserId _userId = 0;
AuthSessionData _data;
AuthSessionSettings _settings;
base::Timer _saveDataTimer;
TimeMs _shouldLockAt = 0;
@@ -405,6 +258,13 @@ private:
const std::unique_ptr<Storage::Uploader> _uploader;
const std::unique_ptr<Storage::Facade> _storage;
const std::unique_ptr<Window::Notifications::System> _notifications;
// _data depends on _downloader / _uploader, including destructor.
const std::unique_ptr<Data::Session> _data;
// _changelogs depends on _data, subscribes on chats loading event.
const std::unique_ptr<Core::Changelogs> _changelogs;
rpl::lifetime _lifetime;
};

View File

@@ -1,614 +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
*/
#include "autoupdater.h"
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#ifdef Q_OS_WIN // use Lzma SDK for win
#include <LzmaLib.h>
#else // Q_OS_WIN
#include <lzma.h>
#endif // else of Q_OS_WIN
#include "application.h"
#include "platform/platform_specific.h"
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
#ifdef Q_OS_WIN
typedef DWORD VerInt;
typedef WCHAR VerChar;
#else // Q_OS_WIN
typedef int VerInt;
typedef wchar_t VerChar;
#endif // Q_OS_WIN
UpdateChecker::UpdateChecker(QThread *thread, const QString &url) : reply(0), already(0), full(0) {
updateUrl = url;
moveToThread(thread);
manager.moveToThread(thread);
App::setProxySettings(manager);
connect(thread, SIGNAL(started()), this, SLOT(start()));
initOutput();
}
void UpdateChecker::initOutput() {
QString fileName;
QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl);
if (m.hasMatch()) {
fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString());
}
if (fileName.isEmpty()) {
fileName = qsl("tupdate-%1").arg(rand_value<uint32>() % 1000000);
}
QString dirStr = cWorkingDir() + qsl("tupdates/");
fileName = dirStr + fileName;
QFileInfo file(fileName);
QDir dir(dirStr);
if (dir.exists()) {
QFileInfoList all = dir.entryInfoList(QDir::Files);
for (QFileInfoList::iterator i = all.begin(), e = all.end(); i != e; ++i) {
if (i->absoluteFilePath() != file.absoluteFilePath()) {
QFile::remove(i->absoluteFilePath());
}
}
} else {
dir.mkdir(dir.absolutePath());
}
outputFile.setFileName(fileName);
if (file.exists()) {
uint64 fullSize = file.size();
if (fullSize < INT_MAX) {
int32 goodSize = (int32)fullSize;
if (goodSize % UpdateChunk) {
goodSize = goodSize - (goodSize % UpdateChunk);
if (goodSize) {
if (outputFile.open(QIODevice::ReadOnly)) {
QByteArray goodData = outputFile.readAll().mid(0, goodSize);
outputFile.close();
if (outputFile.open(QIODevice::WriteOnly)) {
outputFile.write(goodData);
outputFile.close();
QMutexLocker lock(&mutex);
already = goodSize;
}
}
}
} else {
QMutexLocker lock(&mutex);
already = goodSize;
}
}
if (!already) {
QFile::remove(fileName);
}
}
}
void UpdateChecker::start() {
sendRequest();
}
void UpdateChecker::sendRequest() {
QNetworkRequest req(updateUrl);
QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-";
req.setRawHeader("Range", rangeHeaderValue);
req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
if (reply) reply->deleteLater();
reply = manager.get(req);
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(partFinished(qint64,qint64)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(partFailed(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot()));
}
void UpdateChecker::partMetaGot() {
typedef QList<QNetworkReply::RawHeaderPair> Pairs;
Pairs pairs = reply->rawHeaderPairs();
for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) {
if (QString::fromUtf8(i->first).toLower() == "content-range") {
QRegularExpressionMatch m = QRegularExpression(qsl("/(\\d+)([^\\d]|$)")).match(QString::fromUtf8(i->second));
if (m.hasMatch()) {
{
QMutexLocker lock(&mutex);
full = m.captured(1).toInt();
}
Sandbox::updateProgress(already, full);
}
}
}
}
int32 UpdateChecker::ready() {
QMutexLocker lock(&mutex);
return already;
}
int32 UpdateChecker::size() {
QMutexLocker lock(&mutex);
return full;
}
void UpdateChecker::partFinished(qint64 got, qint64 total) {
if (!reply) return;
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (statusCode.isValid()) {
int status = statusCode.toInt();
if (status != 200 && status != 206 && status != 416) {
LOG(("Update Error: Bad HTTP status received in partFinished(): %1").arg(status));
return fatalFail();
}
}
if (!already && !full) {
QMutexLocker lock(&mutex);
full = total;
}
DEBUG_LOG(("Update Info: part %1 of %2").arg(got).arg(total));
if (!outputFile.isOpen()) {
if (!outputFile.open(QIODevice::Append)) {
LOG(("Update Error: Could not open output file '%1' for appending").arg(outputFile.fileName()));
return fatalFail();
}
}
QByteArray r = reply->readAll();
if (!r.isEmpty()) {
outputFile.write(r);
QMutexLocker lock(&mutex);
already += r.size();
}
if (got >= total) {
reply->deleteLater();
reply = 0;
outputFile.close();
unpackUpdate();
} else {
Sandbox::updateProgress(already, full);
}
}
void UpdateChecker::partFailed(QNetworkReply::NetworkError e) {
if (!reply) return;
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
reply->deleteLater();
reply = 0;
if (statusCode.isValid()) {
int status = statusCode.toInt();
if (status == 416) { // Requested range not satisfiable
outputFile.close();
unpackUpdate();
return;
}
}
LOG(("Update Error: failed to download part starting from %1, error %2").arg(already).arg(e));
Sandbox::updateFailed();
}
void UpdateChecker::fatalFail() {
clearAll();
Sandbox::updateFailed();
}
void UpdateChecker::clearAll() {
psDeleteDir(cWorkingDir() + qsl("tupdates"));
}
//QString winapiErrorWrap() {
// WCHAR errMsg[2048];
// DWORD errorCode = GetLastError();
// LPTSTR errorText = NULL, errorTextDefault = L"(Unknown error)";
// FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errorText, 0, 0);
// if (!errorText) {
// errorText = errorTextDefault;
// }
// StringCbPrintf(errMsg, sizeof(errMsg), L"Error code: %d, error message: %s", errorCode, errorText);
// if (errorText != errorTextDefault) {
// LocalFree(errorText);
// }
// return QString::fromWCharArray(errMsg);
//}
void UpdateChecker::unpackUpdate() {
QByteArray packed;
if (!outputFile.open(QIODevice::ReadOnly)) {
LOG(("Update Error: cant read updates file!"));
return fatalFail();
}
#ifdef Q_OS_WIN // use Lzma SDK for win
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
#else // Q_OS_WIN
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header
#endif // Q_OS_WIN
QByteArray compressed = outputFile.readAll();
int32 compressedLen = compressed.size() - hSize;
if (compressedLen <= 0) {
LOG(("Update Error: bad compressed size: %1").arg(compressed.size()));
return fatalFail();
}
outputFile.close();
QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready");
psDeleteDir(tempDirPath);
QDir tempDir(tempDirPath);
if (tempDir.exists() || QFile(readyFilePath).exists()) {
LOG(("Update Error: cant clear tupdates/temp dir!"));
return fatalFail();
}
uchar sha1Buffer[20];
bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen);
if (!goodSha1) {
LOG(("Update Error: bad SHA1 hash of update file!"));
return fatalFail();
}
RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(AppAlphaVersion ? UpdatesPublicAlphaKey : UpdatesPublicKey), -1), 0, 0, 0);
if (!pbKey) {
LOG(("Update Error: cant read public rsa key!"));
return fatalFail();
}
if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature
RSA_free(pbKey);
if (cAlphaVersion() || cBetaVersion()) { // try other public key, if we are in alpha or beta version
pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(AppAlphaVersion ? UpdatesPublicKey : UpdatesPublicAlphaKey), -1), 0, 0, 0);
if (!pbKey) {
LOG(("Update Error: cant read public rsa key!"));
return fatalFail();
}
if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature
RSA_free(pbKey);
LOG(("Update Error: bad RSA signature of update file!"));
return fatalFail();
}
} else {
LOG(("Update Error: bad RSA signature of update file!"));
return fatalFail();
}
}
RSA_free(pbKey);
QByteArray uncompressed;
int32 uncompressedLen;
memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen);
uncompressed.resize(uncompressedLen);
size_t resultLen = uncompressed.size();
#ifdef Q_OS_WIN // use Lzma SDK for win
SizeT srcLen = compressedLen;
int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE);
if (uncompressRes != SZ_OK) {
LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes));
return fatalFail();
}
#else // Q_OS_WIN
lzma_stream stream = LZMA_STREAM_INIT;
lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED);
if (ret != LZMA_OK) {
const char *msg;
switch (ret) {
case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break;
case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break;
case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break;
default: msg = "Unknown error, possibly a bug"; break;
}
LOG(("Error initializing the decoder: %1 (error code %2)").arg(msg).arg(ret));
return fatalFail();
}
stream.avail_in = compressedLen;
stream.next_in = (uint8_t*)(compressed.constData() + hSize);
stream.avail_out = resultLen;
stream.next_out = (uint8_t*)uncompressed.data();
lzma_ret res = lzma_code(&stream, LZMA_FINISH);
if (stream.avail_in) {
LOG(("Error in decompression, %1 bytes left in _in of %2 whole.").arg(stream.avail_in).arg(compressedLen));
return fatalFail();
} else if (stream.avail_out) {
LOG(("Error in decompression, %1 bytes free left in _out of %2 whole.").arg(stream.avail_out).arg(resultLen));
return fatalFail();
}
lzma_end(&stream);
if (res != LZMA_OK && res != LZMA_STREAM_END) {
const char *msg;
switch (res) {
case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break;
case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break;
case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break;
case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break;
case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break;
default: msg = "Unknown error, possibly a bug"; break;
}
LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res));
return fatalFail();
}
#endif // Q_OS_WIN
tempDir.mkdir(tempDir.absolutePath());
quint32 version;
{
QDataStream stream(uncompressed);
stream.setVersion(QDataStream::Qt_5_1);
stream >> version;
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status()));
return fatalFail();
}
quint64 betaVersion = 0;
if (version == 0x7FFFFFFF) { // beta version
stream >> betaVersion;
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read beta version from downloaded stream, status: %1").arg(stream.status()));
return fatalFail();
}
if (!cBetaVersion() || betaVersion <= cBetaVersion()) {
LOG(("Update Error: downloaded beta version %1 is not greater, than mine %2").arg(betaVersion).arg(cBetaVersion()));
return fatalFail();
}
} else if (int32(version) <= AppVersion) {
LOG(("Update Error: downloaded version %1 is not greater, than mine %2").arg(version).arg(AppVersion));
return fatalFail();
}
quint32 filesCount;
stream >> filesCount;
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read files count from downloaded stream, status: %1").arg(stream.status()));
return fatalFail();
}
if (!filesCount) {
LOG(("Update Error: update is empty!"));
return fatalFail();
}
for (uint32 i = 0; i < filesCount; ++i) {
QString relativeName;
quint32 fileSize;
QByteArray fileInnerData;
bool executable = false;
stream >> relativeName >> fileSize >> fileInnerData;
#if defined Q_OS_MAC || defined Q_OS_LINUX
stream >> executable;
#endif // Q_OS_MAC || Q_OS_LINUX
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status()));
return fatalFail();
}
if (fileSize != quint32(fileInnerData.size())) {
LOG(("Update Error: bad file size %1 not matching data size %2").arg(fileSize).arg(fileInnerData.size()));
return fatalFail();
}
QFile f(tempDirPath + '/' + relativeName);
if (!QDir().mkpath(QFileInfo(f).absolutePath())) {
LOG(("Update Error: cant mkpath for file '%1'").arg(tempDirPath + '/' + relativeName));
return fatalFail();
}
if (!f.open(QIODevice::WriteOnly)) {
LOG(("Update Error: cant open file '%1' for writing").arg(tempDirPath + '/' + relativeName));
return fatalFail();
}
auto writtenBytes = f.write(fileInnerData);
if (writtenBytes != fileSize) {
f.close();
LOG(("Update Error: cant write file '%1', desiredSize: %2, write result: %3").arg(tempDirPath + '/' + relativeName).arg(fileSize).arg(writtenBytes));
return fatalFail();
}
f.close();
if (executable) {
QFileDevice::Permissions p = f.permissions();
p |= QFileDevice::ExeOwner | QFileDevice::ExeUser | QFileDevice::ExeGroup | QFileDevice::ExeOther;
f.setPermissions(p);
}
}
// create tdata/version file
tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath());
std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString();
VerInt versionNum = VerInt(version), versionLen = VerInt(versionString.size() * sizeof(VerChar));
VerChar versionStr[32];
memcpy(versionStr, versionString.c_str(), versionLen);
QFile fVersion(tempDirPath + qsl("/tdata/version"));
if (!fVersion.open(QIODevice::WriteOnly)) {
LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version")));
return fatalFail();
}
fVersion.write((const char*)&versionNum, sizeof(VerInt));
if (versionNum == 0x7FFFFFFF) { // beta version
fVersion.write((const char*)&betaVersion, sizeof(quint64));
} else {
fVersion.write((const char*)&versionLen, sizeof(VerInt));
fVersion.write((const char*)&versionStr[0], versionLen);
}
fVersion.close();
}
QFile readyFile(readyFilePath);
if (readyFile.open(QIODevice::WriteOnly)) {
if (readyFile.write("1", 1)) {
readyFile.close();
} else {
LOG(("Update Error: cant write ready file '%1'").arg(readyFilePath));
return fatalFail();
}
} else {
LOG(("Update Error: cant create ready file '%1'").arg(readyFilePath));
return fatalFail();
}
outputFile.remove();
Sandbox::updateReady();
}
UpdateChecker::~UpdateChecker() {
delete reply;
reply = 0;
}
bool checkReadyUpdate() {
QString readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"), readyPath = cWorkingDir() + qsl("tupdates/temp");
if (!QFile(readyFilePath).exists() || cExeName().isEmpty()) {
if (QDir(cWorkingDir() + qsl("tupdates/ready")).exists() || QDir(cWorkingDir() + qsl("tupdates/temp")).exists()) {
UpdateChecker::clearAll();
}
return false;
}
// check ready version
QString versionPath = readyPath + qsl("/tdata/version");
{
QFile fVersion(versionPath);
if (!fVersion.open(QIODevice::ReadOnly)) {
LOG(("Update Error: cant read version file '%1'").arg(versionPath));
UpdateChecker::clearAll();
return false;
}
VerInt versionNum;
if (fVersion.read((char*)&versionNum, sizeof(VerInt)) != sizeof(VerInt)) {
LOG(("Update Error: cant read version from file '%1'").arg(versionPath));
UpdateChecker::clearAll();
return false;
}
if (versionNum == 0x7FFFFFFF) { // beta version
quint64 betaVersion = 0;
if (fVersion.read((char*)&betaVersion, sizeof(quint64)) != sizeof(quint64)) {
LOG(("Update Error: cant read beta version from file '%1'").arg(versionPath));
UpdateChecker::clearAll();
return false;
}
if (!cBetaVersion() || betaVersion <= cBetaVersion()) {
LOG(("Update Error: cant install beta version %1 having beta version %2").arg(betaVersion).arg(cBetaVersion()));
UpdateChecker::clearAll();
return false;
}
} else if (versionNum <= AppVersion) {
LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion));
UpdateChecker::clearAll();
return false;
}
fVersion.close();
}
#ifdef Q_OS_WIN
QString curUpdater = (cExeDir() + qsl("Updater.exe"));
QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Updater.exe"));
#elif defined Q_OS_MAC // Q_OS_WIN
QString curUpdater = (cExeDir() + cExeName() + qsl("/Contents/Frameworks/Updater"));
QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Telegram.app/Contents/Frameworks/Updater"));
#elif defined Q_OS_LINUX // Q_OS_MAC
QString curUpdater = (cExeDir() + qsl("Updater"));
QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Updater"));
#endif // Q_OS_LINUX
if (!updater.exists()) {
QFileInfo current(curUpdater);
if (!current.exists()) {
UpdateChecker::clearAll();
return false;
}
if (!QFile(current.absoluteFilePath()).copy(updater.absoluteFilePath())) {
UpdateChecker::clearAll();
return false;
}
}
#ifdef Q_OS_WIN
if (CopyFile(updater.absoluteFilePath().toStdWString().c_str(), curUpdater.toStdWString().c_str(), FALSE) == FALSE) {
DWORD errorCode = GetLastError();
if (errorCode == ERROR_ACCESS_DENIED) { // we are in write-protected dir, like Program Files
cSetWriteProtected(true);
return true;
} else {
UpdateChecker::clearAll();
return false;
}
}
if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) {
UpdateChecker::clearAll();
return false;
}
#elif defined Q_OS_MAC // Q_OS_WIN
QDir().mkpath(QFileInfo(curUpdater).absolutePath());
DEBUG_LOG(("Update Info: moving %1 to %2...").arg(updater.absoluteFilePath()).arg(curUpdater));
if (!objc_moveFile(updater.absoluteFilePath(), curUpdater)) {
UpdateChecker::clearAll();
return false;
}
#elif defined Q_OS_LINUX // Q_OS_MAC
if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) {
UpdateChecker::clearAll();
return false;
}
#endif // Q_OS_LINUX
return true;
}
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
QString countBetaVersionSignature(uint64 version) { // duplicated in packer.cpp
if (cBetaPrivateKey().isEmpty()) {
LOG(("Error: Trying to count beta version signature without beta private key!"));
return QString();
}
QByteArray signedData = (qstr("TelegramBeta_") + QString::number(version, 16).toLower()).toUtf8();
static const int32 shaSize = 20, keySize = 128;
uchar sha1Buffer[shaSize];
hashSha1(signedData.constData(), signedData.size(), sha1Buffer); // count sha1
uint32 siglen = 0;
RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast<char*>(cBetaPrivateKey().constData()), -1), 0, 0, 0);
if (!prKey) {
LOG(("Error: Could not read beta private key!"));
return QString();
}
if (RSA_size(prKey) != keySize) {
LOG(("Error: Bad beta private key size: %1").arg(RSA_size(prKey)));
RSA_free(prKey);
return QString();
}
QByteArray signature;
signature.resize(keySize);
if (RSA_sign(NID_sha1, (const uchar*)(sha1Buffer), shaSize, (uchar*)(signature.data()), &siglen, prKey) != 1) { // count signature
LOG(("Error: Counting beta version signature failed!"));
RSA_free(prKey);
return QString();
}
RSA_free(prKey);
if (siglen != keySize) {
LOG(("Error: Bad beta version signature length: %1").arg(siglen));
return QString();
}
signature = signature.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
signature = signature.replace('-', '8').replace('_', 'B');
return QString::fromUtf8(signature.mid(19, 32));
}

View File

@@ -1,63 +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
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QNetworkReply>
class UpdateChecker : public QObject {
Q_OBJECT
public:
UpdateChecker(QThread *thread, const QString &url);
void unpackUpdate();
int32 ready();
int32 size();
static void clearAll();
~UpdateChecker();
public slots:
void start();
void partMetaGot();
void partFinished(qint64 got, qint64 total);
void partFailed(QNetworkReply::NetworkError e);
void sendRequest();
private:
void initOutput();
void fatalFail();
QString updateUrl;
QNetworkAccessManager manager;
QNetworkReply *reply;
int32 already, full;
QFile outputFile;
QMutex mutex;
};
bool checkReadyUpdate();
#else // TDESKTOP_DISABLE_AUTOUPDATE
class UpdateChecker : public QObject {
Q_OBJECT
};
#endif // TDESKTOP_DISABLE_AUTOUPDATE
QString countBetaVersionSignature(uint64 version);

View File

@@ -47,6 +47,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#define ARCH_CPU_X86_FAMILY 1
#define ARCH_CPU_X86 1
#define ARCH_CPU_32_BITS 1
#elif defined(__aarch64__)
#define ARCH_CPU_64_BITS 1
#elif defined(_M_ARM) || defined(__arm__)
#define ARCH_CPU_32_BITS 1
#else
#error Please add support for your architecture in base/build_config.h
#endif

View File

@@ -0,0 +1,137 @@
/*
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 <gsl/gsl_byte>
namespace bytes {
using span = gsl::span<gsl::byte>;
using const_span = gsl::span<const gsl::byte>;
using vector = std::vector<gsl::byte>;
template <
typename Container,
typename = std::enable_if_t<!std::is_const_v<Container>>>
inline span make_span(Container &container) {
return gsl::as_writeable_bytes(gsl::make_span(container));
}
template <typename Container>
inline const_span make_span(const Container &container) {
return gsl::as_bytes(gsl::make_span(container));
}
template <typename Type, std::ptrdiff_t Extent>
inline span make_span(gsl::span<Type, Extent> container) {
return gsl::as_writeable_bytes(container);
}
template <typename Type, std::ptrdiff_t Extent>
inline const_span make_span(gsl::span<const Type, Extent> container) {
return gsl::as_bytes(container);
}
template <typename Type>
inline span make_span(Type *value, std::size_t count) {
return gsl::as_writeable_bytes(gsl::make_span(value, count));
}
template <typename Type>
inline const_span make_span(const Type *value, std::size_t count) {
return gsl::as_bytes(gsl::make_span(value, count));
}
template <typename Container>
inline vector make_vector(const Container &container) {
const auto buffer = bytes::make_span(container);
return { buffer.begin(), buffer.end() };
}
inline void copy(span destination, const_span source) {
Expects(destination.size() >= source.size());
memcpy(destination.data(), source.data(), source.size());
}
inline void move(span destination, const_span source) {
Expects(destination.size() >= source.size());
memmove(destination.data(), source.data(), source.size());
}
inline void set_with_const(span destination, gsl::byte value) {
memset(
destination.data(),
gsl::to_integer<unsigned char>(value),
destination.size());
}
inline int compare(const_span a, const_span b) {
const auto aSize = a.size(), bSize = b.size();
return (aSize > bSize)
? 1
: (aSize < bSize)
? -1
: memcmp(a.data(), b.data(), aSize);
}
namespace details {
template <typename Arg>
std::size_t spansLength(Arg &&arg) {
return bytes::make_span(arg).size();
}
template <typename Arg, typename ...Args>
std::size_t spansLength(Arg &&arg, Args &&...args) {
return bytes::make_span(arg).size() + spansLength(args...);
}
template <typename Arg>
void spansAppend(span destination, Arg &&arg) {
bytes::copy(destination, bytes::make_span(arg));
}
template <typename Arg, typename ...Args>
void spansAppend(span destination, Arg &&arg, Args &&...args) {
const auto data = bytes::make_span(arg);
bytes::copy(destination, data);
spansAppend(destination.subspan(data.size()), args...);
}
} // namespace details
template <
typename ...Args,
typename = std::enable_if_t<(sizeof...(Args) > 1)>>
vector concatenate(Args &&...args) {
const auto size = details::spansLength(args...);
auto result = vector(size);
details::spansAppend(make_span(result), args...);
return result;
}
template <
typename SpanRange>
vector concatenate(SpanRange args) {
auto size = std::size_t(0);
for (const auto &arg : args) {
size += bytes::make_span(arg).size();
}
auto result = vector(size);
auto buffer = make_span(result);
for (const auto &arg : args) {
const auto part = bytes::make_span(arg);
bytes::copy(buffer, part);
buffer = buffer.subspan(part.size());
}
return result;
}
} // namespace bytes

View File

@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <openssl/bn.h>
#include <openssl/sha.h>
#include <openssl/rand.h>
#include "base/bytes.h"
namespace openssl {
@@ -223,3 +224,13 @@ inline int FillRandom(base::byte_span bytes) {
}
} // namespace openssl
namespace bytes {
inline void set_random(span destination) {
RAND_bytes(
reinterpret_cast<unsigned char*>(destination.data()),
destination.size());
}
} // namespace bytes

View File

@@ -38,4 +38,10 @@ QMap<QString, QString> url_parse_params(
return result;
}
bool is_ipv6(const QString &ip) {
//static const auto regexp = QRegularExpression("^[a-fA-F0-9:]+$");
//return regexp.match(ip).hasMatch();
return ip.indexOf(':') >= 0;
}
} // namespace qthelp

View File

@@ -24,4 +24,6 @@ enum class UrlParamNameTransform {
// Parses a string like "p1=v1&p2=v2&..&pn=vn" to a map.
QMap<QString, QString> url_parse_params(const QString &params, UrlParamNameTransform transform = UrlParamNameTransform::NoTransform);
bool is_ipv6(const QString &ip);
} // namespace qthelp

View File

@@ -31,7 +31,7 @@ const RuntimeComposerMetadata *GetRuntimeComposerMetadata(uint64 mask) {
return i.value();
}
const RuntimeComposerMetadata *RuntimeComposer::ZeroRuntimeComposerMetadata = GetRuntimeComposerMetadata(0);
const RuntimeComposerMetadata *RuntimeComposerBase::ZeroRuntimeComposerMetadata = GetRuntimeComposerMetadata(0);
RuntimeComponentWrapStruct RuntimeComponentWraps[64];

View File

@@ -7,8 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
template <typename Base>
class RuntimeComposer;
typedef void(*RuntimeComponentConstruct)(void *location, RuntimeComposer *composer);
class RuntimeComposerBase;
typedef void(*RuntimeComponentConstruct)(void *location, RuntimeComposerBase *composer);
typedef void(*RuntimeComponentDestruct)(void *location);
typedef void(*RuntimeComponentMove)(void *location, void *waslocation);
@@ -38,8 +41,10 @@ struct CeilDivideMinimumOne {
extern RuntimeComponentWrapStruct RuntimeComponentWraps[64];
extern QAtomicInt RuntimeComponentIndexLast;
template <typename Type>
template <typename Type, typename Base>
struct RuntimeComponent {
using RuntimeComponentBase = Base;
RuntimeComponent() {
// While there is no std::aligned_alloc().
static_assert(alignof(Type) <= alignof(std::max_align_t), "Components should align to std::max_align_t!");
@@ -76,7 +81,7 @@ struct RuntimeComponent {
}
protected:
static void RuntimeComponentConstruct(void *location, RuntimeComposer *composer) {
static void RuntimeComponentConstruct(void *location, RuntimeComposerBase *composer) {
new (location) Type();
}
static void RuntimeComponentDestruct(void *location) {
@@ -134,9 +139,9 @@ private:
const RuntimeComposerMetadata *GetRuntimeComposerMetadata(uint64 mask);
class RuntimeComposer {
class RuntimeComposerBase {
public:
RuntimeComposer(uint64 mask = 0) : _data(zerodata()) {
RuntimeComposerBase(uint64 mask = 0) : _data(zerodata()) {
if (mask) {
auto meta = GetRuntimeComposerMetadata(mask);
@@ -169,9 +174,9 @@ public:
}
}
}
RuntimeComposer(const RuntimeComposer &other) = delete;
RuntimeComposer &operator=(const RuntimeComposer &other) = delete;
~RuntimeComposer() {
RuntimeComposerBase(const RuntimeComposerBase &other) = delete;
RuntimeComposerBase &operator=(const RuntimeComposerBase &other) = delete;
~RuntimeComposerBase() {
if (_data != zerodata()) {
auto meta = _meta();
for (int i = 0; i < meta->last; ++i) {
@@ -184,45 +189,40 @@ public:
}
}
template <typename Type>
bool Has() const {
return (_meta()->offsets[Type::Index()] >= sizeof(_meta()));
}
template <typename Type>
Type *Get() {
return static_cast<Type*>(_dataptr(_meta()->offsets[Type::Index()]));
}
template <typename Type>
const Type *Get() const {
return static_cast<const Type*>(_dataptr(_meta()->offsets[Type::Index()]));
}
protected:
void UpdateComponents(uint64 mask = 0) {
if (!_meta()->equals(mask)) {
RuntimeComposer tmp(mask);
tmp.swap(*this);
if (_data != zerodata() && tmp._data != zerodata()) {
auto meta = _meta(), wasmeta = tmp._meta();
for (int i = 0; i < meta->last; ++i) {
auto offset = meta->offsets[i];
auto wasoffset = wasmeta->offsets[i];
if (offset >= sizeof(_meta()) && wasoffset >= sizeof(_meta())) {
RuntimeComponentWraps[i].Move(_dataptrunsafe(offset), tmp._dataptrunsafe(wasoffset));
}
bool UpdateComponents(uint64 mask = 0) {
if (_meta()->equals(mask)) {
return false;
}
RuntimeComposerBase result(mask);
result.swap(*this);
if (_data != zerodata() && result._data != zerodata()) {
const auto meta = _meta();
const auto wasmeta = result._meta();
for (auto i = 0; i != meta->last; ++i) {
const auto offset = meta->offsets[i];
const auto wasoffset = wasmeta->offsets[i];
if (offset >= sizeof(_meta())
&& wasoffset >= sizeof(_meta())) {
RuntimeComponentWraps[i].Move(
_dataptrunsafe(offset),
result._dataptrunsafe(wasoffset));
}
}
}
return true;
}
void AddComponents(uint64 mask = 0) {
UpdateComponents(_meta()->maskadd(mask));
bool AddComponents(uint64 mask = 0) {
return UpdateComponents(_meta()->maskadd(mask));
}
void RemoveComponents(uint64 mask = 0) {
UpdateComponents(_meta()->maskremove(mask));
bool RemoveComponents(uint64 mask = 0) {
return UpdateComponents(_meta()->maskremove(mask));
}
private:
template <typename Base>
friend class RuntimeComposer;
static const RuntimeComposerMetadata *ZeroRuntimeComposerMetadata;
static void *zerodata() {
return &ZeroRuntimeComposerMetadata;
@@ -239,8 +239,41 @@ private:
}
void *_data = nullptr;
void swap(RuntimeComposer &other) {
void swap(RuntimeComposerBase &other) {
std::swap(_data, other._data);
}
};
template <typename Base>
class RuntimeComposer : public RuntimeComposerBase {
public:
using RuntimeComposerBase::RuntimeComposerBase;
template <
typename Type,
typename = std::enable_if_t<std::is_same_v<
typename Type::RuntimeComponentBase,
Base>>>
bool Has() const {
return (_meta()->offsets[Type::Index()] >= sizeof(_meta()));
}
template <
typename Type,
typename = std::enable_if_t<std::is_same_v<
typename Type::RuntimeComponentBase,
Base>>>
Type *Get() {
return static_cast<Type*>(_dataptr(_meta()->offsets[Type::Index()]));
}
template <
typename Type,
typename = std::enable_if_t<std::is_same_v<
typename Type::RuntimeComponentBase,
Base>>>
const Type *Get() const {
return static_cast<const Type*>(_dataptr(_meta()->offsets[Type::Index()]));
}
};

View File

@@ -17,12 +17,26 @@ QObject *TimersAdjuster() {
} // namespace
Timer::Timer(base::lambda<void()> callback) : QObject(nullptr)
Timer::Timer(
not_null<QThread*> thread,
base::lambda<void()> callback)
: Timer(std::move(callback)) {
moveToThread(thread);
}
Timer::Timer(base::lambda<void()> callback)
: QObject(nullptr)
, _callback(std::move(callback))
, _type(Qt::PreciseTimer)
, _adjusted(false) {
setRepeat(Repeat::Interval);
connect(TimersAdjuster(), &QObject::destroyed, this, [this] { adjust(); }, Qt::QueuedConnection);
connect(
TimersAdjuster(),
&QObject::destroyed,
this,
[this] { adjust(); },
Qt::QueuedConnection);
}
void Timer::start(TimeMs timeout, Qt::TimerType type, Repeat repeat) {
@@ -56,7 +70,11 @@ TimeMs Timer::remainingTime() const {
void Timer::Adjust() {
QObject emitter;
connect(&emitter, &QObject::destroyed, TimersAdjuster(), &QObject::destroyed);
connect(
&emitter,
&QObject::destroyed,
TimersAdjuster(),
&QObject::destroyed);
}
void Timer::adjust() {
@@ -70,6 +88,7 @@ void Timer::adjust() {
void Timer::setTimeout(TimeMs timeout) {
Expects(timeout >= 0 && timeout <= std::numeric_limits<int>::max());
_timeout = static_cast<unsigned int>(timeout);
}
@@ -93,8 +112,12 @@ void Timer::timerEvent(QTimerEvent *e) {
}
}
int DelayedCallTimer::call(TimeMs timeout, lambda_once<void()> callback, Qt::TimerType type) {
int DelayedCallTimer::call(
TimeMs timeout,
lambda_once<void()> callback,
Qt::TimerType type) {
Expects(timeout >= 0);
if (!callback) {
return 0;
}
@@ -108,7 +131,7 @@ int DelayedCallTimer::call(TimeMs timeout, lambda_once<void()> callback, Qt::Tim
void DelayedCallTimer::cancel(int callId) {
if (callId) {
killTimer(callId);
_callbacks.erase(callId);
_callbacks.remove(callId);
}
}

View File

@@ -14,7 +14,10 @@ namespace base {
class Timer final : private QObject {
public:
Timer(base::lambda<void()> callback = base::lambda<void()>());
explicit Timer(
not_null<QThread*> thread,
base::lambda<void()> callback = nullptr);
explicit Timer(base::lambda<void()> callback = nullptr);
static Qt::TimerType DefaultType(TimeMs timeout) {
constexpr auto kThreshold = TimeMs(1000);
@@ -85,17 +88,23 @@ private:
class DelayedCallTimer final : private QObject {
public:
int call(TimeMs timeout, lambda_once<void()> callback) {
return call(timeout, std::move(callback), Timer::DefaultType(timeout));
return call(
timeout,
std::move(callback),
Timer::DefaultType(timeout));
}
int call(TimeMs timeout, lambda_once<void()> callback, Qt::TimerType type);
int call(
TimeMs timeout,
lambda_once<void()> callback,
Qt::TimerType type);
void cancel(int callId);
protected:
void timerEvent(QTimerEvent *e) override;
private:
std::map<int, lambda_once<void()>> _callbacks; // Better to use flatmap.
base::flat_map<int, lambda_once<void()>> _callbacks;
};

View File

@@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "autoupdater.h"
#include "boxes/confirm_box.h"
#include "application.h"
#include "ui/widgets/buttons.h"
@@ -18,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_boxes.h"
#include "platform/platform_file_utilities.h"
#include "core/click_handler_types.h"
#include "core/update_checker.h"
AboutBox::AboutBox(QWidget *parent)
: _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink)
@@ -68,7 +68,7 @@ void AboutBox::showVersionHistory() {
case dbipLinux32: url += qsl("linux32/%1.tar.xz"); break;
case dbipLinux64: url += qsl("linux/%1.tar.xz"); break;
}
url = url.arg(qsl("tbeta%1_%2").arg(cRealBetaVersion()).arg(countBetaVersionSignature(cRealBetaVersion())));
url = url.arg(qsl("tbeta%1_%2").arg(cRealBetaVersion()).arg(Core::countBetaVersionSignature(cRealBetaVersion())));
Application::clipboard()->setText(url);

View File

@@ -19,12 +19,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwidget.h"
#include "mainwindow.h"
QPointer<Ui::RoundButton> BoxContent::addButton(base::lambda<QString()> textFactory, base::lambda<void()> clickCallback) {
return addButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton);
QPointer<Ui::RoundButton> BoxContent::addButton(
base::lambda<QString()> textFactory,
base::lambda<void()> clickCallback) {
return addButton(
std::move(textFactory),
std::move(clickCallback),
st::defaultBoxButton);
}
QPointer<Ui::RoundButton> BoxContent::addLeftButton(base::lambda<QString()> textFactory, base::lambda<void()> clickCallback) {
return getDelegate()->addLeftButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton);
QPointer<Ui::RoundButton> BoxContent::addLeftButton(
base::lambda<QString()> textFactory,
base::lambda<void()> clickCallback) {
return getDelegate()->addLeftButton(
std::move(textFactory),
std::move(clickCallback),
st::defaultBoxButton);
}
void BoxContent::setInner(object_ptr<TWidget> inner) {
@@ -117,7 +127,7 @@ void BoxContent::updateShadowsVisibility() {
(top > 0 || _innerTopSkip > 0),
anim::type::normal);
_bottomShadow->toggle(
(top < _scroll->scrollTopMax()),
(top < _scroll->scrollTopMax() || _innerBottomSkip > 0),
anim::type::normal);
}
@@ -145,6 +155,16 @@ void BoxContent::setInnerTopSkip(int innerTopSkip, bool scrollBottomFixed) {
}
}
void BoxContent::setInnerBottomSkip(int innerBottomSkip) {
if (_innerBottomSkip != innerBottomSkip) {
auto delta = innerBottomSkip - _innerBottomSkip;
_innerBottomSkip = innerBottomSkip;
if (_scroll && width() > 0) {
updateScrollAreaGeometry();
}
}
}
void BoxContent::setInnerVisible(bool scrollAreaVisible) {
if (_scroll) {
_scroll->setVisible(scrollAreaVisible);
@@ -169,13 +189,15 @@ void BoxContent::resizeEvent(QResizeEvent *e) {
}
void BoxContent::updateScrollAreaGeometry() {
auto newScrollHeight = height() - _innerTopSkip;
auto newScrollHeight = height() - _innerTopSkip - _innerBottomSkip;
auto changed = (_scroll->height() != newScrollHeight);
_scroll->setGeometryToLeft(0, _innerTopSkip, width(), newScrollHeight);
_topShadow->entity()->resize(width(), st::lineWidth);
_topShadow->moveToLeft(0, _innerTopSkip);
_bottomShadow->entity()->resize(width(), st::lineWidth);
_bottomShadow->moveToLeft(0, height() - st::lineWidth);
_bottomShadow->moveToLeft(
0,
height() - _innerBottomSkip - st::lineWidth);
if (changed) {
updateInnerVisibleTopBottom();
@@ -184,7 +206,7 @@ void BoxContent::updateScrollAreaGeometry() {
(top > 0 || _innerTopSkip > 0),
anim::type::instant);
_bottomShadow->toggle(
(top < _scroll->scrollTopMax()),
(top < _scroll->scrollTopMax() || _innerBottomSkip > 0),
anim::type::instant);
}
}

View File

@@ -130,19 +130,29 @@ protected:
getDelegate()->setDimensions(newWidth, maxHeight);
}
void setInnerTopSkip(int topSkip, bool scrollBottomFixed = false);
void setInnerBottomSkip(int bottomSkip);
template <typename Widget>
QPointer<Widget> setInnerWidget(object_ptr<Widget> inner, const style::ScrollArea &st, int topSkip = 0) {
QPointer<Widget> setInnerWidget(
object_ptr<Widget> inner,
const style::ScrollArea &st,
int topSkip = 0,
int bottomSkip = 0) {
auto result = QPointer<Widget>(inner.data());
setInnerTopSkip(topSkip);
setInnerBottomSkip(bottomSkip);
setInner(std::move(inner), st);
return result;
}
template <typename Widget>
QPointer<Widget> setInnerWidget(object_ptr<Widget> inner, int topSkip = 0) {
QPointer<Widget> setInnerWidget(
object_ptr<Widget> inner,
int topSkip = 0,
int bottomSkip = 0) {
auto result = QPointer<Widget>(inner.data());
setInnerTopSkip(topSkip);
setInnerBottomSkip(bottomSkip);
setInner(std::move(inner));
return result;
}
@@ -183,6 +193,7 @@ private:
bool _preparing = false;
bool _noContentMargin = false;
int _innerTopSkip = 0;
int _innerBottomSkip = 0;
object_ptr<Ui::ScrollArea> _scroll = { nullptr };
object_ptr<Ui::FadeShadow> _topShadow = { nullptr };
object_ptr<Ui::FadeShadow> _bottomShadow = { nullptr };

View File

@@ -33,8 +33,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kMaxGroupChannelTitle = 255;
constexpr auto kMaxChannelDescription = 255;
constexpr auto kMaxChannelDescription = 255; // See also edit_peer_info_box.
constexpr auto kMaxBioLength = 70;
constexpr auto kMinUsernameLength = 5;
style::InputField CreateBioFieldStyle() {
auto result = st::newGroupDescription;
@@ -241,19 +242,23 @@ bool AddContactBox::onSaveUserFail(const RPCError &error) {
void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
if (!isBoxShown() || !App::main()) return;
auto &d = res.c_contacts_importedContacts();
const auto &d = res.c_contacts_importedContacts();
App::feedUsers(d.vusers);
auto &v = d.vimported.v;
UserData *user = nullptr;
if (!v.isEmpty()) {
auto &c = v.front().c_importedContact();
if (c.vclient_id.v != _contactId) return;
user = App::userLoaded(c.vuser_id.v);
}
const auto &v = d.vimported.v;
const auto user = [&]() -> UserData* {
if (!v.isEmpty()) {
auto &c = v.front().c_importedContact();
if (c.vclient_id.v == _contactId) {
return App::userLoaded(c.vuser_id.v);
}
}
return nullptr;
}();
if (user) {
Notify::userIsContactChanged(user, true);
if (user->contactStatus() == UserData::ContactStatus::Contact) {
Ui::showPeerHistory(user, ShowAtTheEndMsgId);
}
Ui::hideLayer();
} else {
hideChildren();
@@ -763,7 +768,7 @@ void SetupChannelBox::onChange() {
return;
}
}
if (name.size() < MinUsernameLength) {
if (name.size() < kMinUsernameLength) {
if (_errorText != lang(lng_create_channel_link_too_short)) {
_errorText = lang(lng_create_channel_link_too_short);
update();
@@ -784,9 +789,14 @@ void SetupChannelBox::onCheck() {
MTP::cancel(_checkRequestId);
}
QString link = _link->text().trimmed();
if (link.size() >= MinUsernameLength) {
if (link.size() >= kMinUsernameLength) {
_checkUsername = link;
_checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string(link)), rpcDone(&SetupChannelBox::onCheckDone), rpcFail(&SetupChannelBox::onCheckFail));
_checkRequestId = MTP::send(
MTPchannels_CheckUsername(
_channel->inputChannel,
MTP_string(link)),
rpcDone(&SetupChannelBox::onCheckDone),
rpcFail(&SetupChannelBox::onCheckFail));
}
}

View File

@@ -117,6 +117,11 @@ boxLabel: FlatLabel(defaultFlatLabel) {
align: align(topleft);
style: boxLabelStyle;
}
boxDividerLabel: FlatLabel(boxLabel) {
minWidth: 245px;
textFg: windowSubTextFg;
style: defaultTextStyle;
}
countryRowHeight: 36px;
countryRowNameFont: semiboldFont;
@@ -711,3 +716,68 @@ sendMediaFileThumbSize: 64px;
sendMediaFileThumbSkip: 10px;
sendMediaFileNameTop: 7px;
sendMediaFileStatusTop: 37px;
proxyUsePadding: margins(22px, 6px, 22px, 5px);
proxyTryIPv6Padding: margins(22px, 8px, 22px, 5px);
proxyRowPadding: margins(22px, 8px, 8px, 8px);
proxyRowIconSkip: 32px;
proxyRowSkip: 2px;
proxyRowRipple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
proxyRowSelectedIcon: icon {{ "passport_ready", windowActiveTextFg }};
proxyRowTitleFg: windowFg;
proxyRowTitlePalette: TextPalette(defaultTextPalette) {
linkFg: windowSubTextFg;
}
proxyRowTitleStyle: TextStyle(defaultTextStyle) {
font: semiboldFont;
linkFont: normalFont;
linkFontOver: normalFont;
}
proxyRowStatusFg: windowSubTextFg;
proxyRowStatusFgOnline: windowActiveTextFg;
proxyRowStatusFgOffline: boxTextFgError;
proxyRowStatusFgAvailable: boxTextFgGood;
proxyRowEdit: IconButton(defaultIconButton) {
width: 40px;
height: 40px;
icon: icon {{ "settings_edit_name", menuIconFg }};
iconOver: icon {{ "settings_edit_name", menuIconFgOver }};
iconPosition: point(12px, 13px);
rippleAreaSize: 40px;
rippleAreaPosition: point(0px, 0px);
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
}
proxyEditTitle: FlatLabel(defaultFlatLabel) {
style: TextStyle(defaultTextStyle) {
font: autoDownloadTitleFont;
}
textFg: boxTitleFg;
}
proxyEditTitlePadding: margins(22px, 16px, 22px, 0px);
proxyEditTypePadding: margins(22px, 4px, 22px, 8px);
proxyEditInputPadding: margins(22px, 0px, 22px, 0px);
proxyEditSkip: 16px;
proxyEmptyListLabel: FlatLabel(defaultFlatLabel) {
align: align(top);
textFg: windowSubTextFg;
}
proxyEmptyListPadding: margins(22px, 48px, 22px, 0px);
proxyCheckingPosition: point(2px, 5px);
proxyCheckingSkip: 6px;
proxyCheckingAnimation: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
color: windowSubTextFg;
thickness: 1px;
size: size(8px, 8px);
}
proxyDropdownDownPosition: point(-2px, 35px);
proxyDropdownUpPosition: point(-2px, 20px);
proxyAboutPadding: margins(22px, 7px, 22px, 14px);

View File

@@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h"
#include "apiwrap.h"
#include "application.h"
#include "history/history.h"
#include "history/history_item.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
@@ -20,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/empty_userpic.h"
#include "core/click_handler_types.h"
#include "storage/localstorage.h"
#include "data/data_session.h"
#include "auth_session.h"
#include "observer_peer.h"
@@ -457,7 +460,7 @@ void DeleteMessagesBox::prepare() {
} else {
text = _singleItem ? lang(lng_selected_delete_sure_this) : lng_selected_delete_sure(lt_count, _ids.size());
auto canDeleteAllForEveryone = true;
auto now = ::date(unixtime());
auto now = unixtime();
auto deleteForUser = (UserData*)nullptr;
auto peer = (PeerData*)nullptr;
auto forEveryoneText = lang(lng_delete_for_everyone_check);
@@ -565,28 +568,28 @@ void DeleteMessagesBox::deleteAndClear() {
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg))));
}
if (_deleteAll && _deleteAll->checked()) {
App::main()->deleteAllFromUser(
Auth().api().deleteAllFromUser(
_moderateInChannel,
_moderateFrom);
}
}
if (!_singleItem) {
App::main()->clearSelectedItems();
if (_deleteConfirmedCallback) {
_deleteConfirmedCallback();
}
QMap<PeerData*, QVector<MTPint>> idsByPeer;
for_const (auto fullId, _ids) {
if (auto item = App::histItemById(fullId)) {
for (const auto itemId : _ids) {
if (auto item = App::histItemById(itemId)) {
auto history = item->history();
auto wasOnServer = (item->id > 0);
auto wasLast = (history->lastMsg == item);
auto wasLast = (history->lastMessage() == item);
item->destroy();
if (wasOnServer) {
idsByPeer[history->peer].push_back(MTP_int(fullId.msg));
} else if (wasLast) {
App::main()->checkPeerHistory(history->peer);
idsByPeer[history->peer].push_back(MTP_int(itemId.msg));
} else if (wasLast && !history->lastMessageKnown()) {
Auth().api().requestDialogEntry(history);
}
}
}
@@ -596,6 +599,7 @@ void DeleteMessagesBox::deleteAndClear() {
App::main()->deleteMessages(i.key(), i.value(), forEveryone);
}
Ui::hideLayer();
Auth().data().sendHistoryChangeNotifications();
}
ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, bool isChannel, const MTPChatPhoto &photo, int count, const QVector<UserData*> &participants)
@@ -637,7 +641,7 @@ ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, bool isChanne
}
void ConfirmInviteBox::prepare() {
addButton(langFactory(lng_group_invite_join), [this] {
addButton(langFactory(lng_group_invite_join), [] {
if (auto main = App::main()) {
main->onInviteImport();
}

View File

@@ -166,6 +166,10 @@ public:
bool suggestModerateActions);
DeleteMessagesBox(QWidget*, MessageIdsList &&selected);
void setDeleteConfirmedCallback(base::lambda<void()> callback) {
_deleteConfirmedCallback = std::move(callback);
}
protected:
void prepare() override;
@@ -188,6 +192,8 @@ private:
object_ptr<Ui::Checkbox> _reportSpam = { nullptr };
object_ptr<Ui::Checkbox> _deleteAll = { nullptr };
base::lambda<void()> _deleteConfirmedCallback;
};
class ConfirmInviteBox : public BoxContent, public RPCSender {

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/abstract_box.h"
#include "base/timer.h"
#include "mtproto/connection_abstract.h"
namespace Ui {
class InputField;
@@ -24,9 +26,13 @@ class ConnectionBox : public BoxContent {
Q_OBJECT
public:
using Type = ProxyData::Type;
ConnectionBox(QWidget *parent);
static void ShowApplyProxyConfirmation(const QMap<QString, QString> &fields);
static void ShowApplyProxyConfirmation(
Type type,
const QMap<QString, QString> &fields);
protected:
void prepare() override;
@@ -40,19 +46,20 @@ private slots:
void onSave();
private:
void typeChanged(DBIConnectionType type);
void typeChanged(Type type);
void updateControlsVisibility();
void updateControlsPosition();
bool badProxyValue() const;
bool proxyFieldsVisible() const;
object_ptr<Ui::InputField> _hostInput;
object_ptr<Ui::PortInput> _portInput;
object_ptr<Ui::InputField> _userInput;
object_ptr<Ui::PasswordInput> _passwordInput;
std::shared_ptr<Ui::RadioenumGroup<DBIConnectionType>> _typeGroup;
object_ptr<Ui::Radioenum<DBIConnectionType>> _autoRadio;
object_ptr<Ui::Radioenum<DBIConnectionType>> _httpProxyRadio;
object_ptr<Ui::Radioenum<DBIConnectionType>> _tcpProxyRadio;
std::shared_ptr<Ui::RadioenumGroup<Type>> _typeGroup;
object_ptr<Ui::Radioenum<Type>> _autoRadio;
object_ptr<Ui::Radioenum<Type>> _httpProxyRadio;
object_ptr<Ui::Radioenum<Type>> _tcpProxyRadio;
object_ptr<Ui::Checkbox> _tryIPv6;
};
@@ -84,3 +91,90 @@ private:
int _sectionHeight = 0;
};
class ProxiesBoxController : public base::Subscriber {
public:
using Type = ProxyData::Type;
ProxiesBoxController();
static object_ptr<BoxContent> CreateOwningBox();
object_ptr<BoxContent> create();
enum class ItemState {
Connecting,
Online,
Checking,
Available,
Unavailable
};
struct ItemView {
int id = 0;
QString type;
QString host;
uint32 port = 0;
int ping = 0;
bool selected = false;
bool deleted = false;
bool supportsShare = false;
bool supportsCalls = false;
ItemState state = ItemState::Checking;
};
void deleteItem(int id);
void restoreItem(int id);
void shareItem(int id);
void applyItem(int id);
object_ptr<BoxContent> editItemBox(int id);
object_ptr<BoxContent> addNewItemBox();
bool setProxyEnabled(bool enabled);
void setProxyForCalls(bool enabled);
void setTryIPv6(bool enabled);
rpl::producer<bool> proxyEnabledValue() const;
rpl::producer<ItemView> views() const;
~ProxiesBoxController();
private:
using Checker = MTP::internal::ConnectionPointer;
struct Item {
int id = 0;
ProxyData data;
bool deleted = false;
Checker checker;
Checker checkerv6;
ItemState state = ItemState::Checking;
int ping = 0;
};
std::vector<Item>::iterator findById(int id);
std::vector<Item>::iterator findByProxy(const ProxyData &proxy);
void setDeleted(int id, bool deleted);
void updateView(const Item &item);
void share(const ProxyData &proxy);
void applyChanges();
void saveDelayed();
void refreshChecker(Item &item);
void setupChecker(int id, const Checker &checker);
void replaceItemWith(
std::vector<Item>::iterator which,
std::vector<Item>::iterator with);
void replaceItemValue(
std::vector<Item>::iterator which,
const ProxyData &proxy);
void addNewItem(const ProxyData &proxy);
int _idCounter = 0;
std::vector<Item> _list;
rpl::event_stream<ItemView> _views;
base::Timer _saveTimer;
rpl::event_stream<bool> _proxyEnabledChanges;
ProxyData _lastSelectedProxy;
bool _lastSelectedProxyUsed = false;
};

View File

@@ -10,68 +10,47 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h"
#include "ui/text_options.h"
#include "media/media_clip_reader.h"
#include "history/history_media_types.h"
#include "history/history.h"
#include "history/history_item.h"
#include "data/data_media_types.h"
#include "data/data_photo.h"
#include "data/data_document.h"
#include "lang/lang_keys.h"
#include "window/window_controller.h"
#include "mainwidget.h"
#include "layout.h"
#include "styles/style_history.h"
#include "styles/style_boxes.h"
EditCaptionBox::EditCaptionBox(
QWidget*,
not_null<HistoryMedia*> media,
FullMsgId msgId)
: _msgId(msgId) {
Expects(media->canEditCaption());
not_null<HistoryItem*> item)
: _msgId(item->fullId()) {
Expects(item->media() != nullptr);
Expects(item->media()->allowsEditCaption());
QSize dimensions;
ImagePtr image;
QString caption;
DocumentData *doc = nullptr;
switch (media->type()) {
case MediaTypeGif: {
_animated = true;
doc = static_cast<HistoryGif*>(media.get())->getDocument();
dimensions = doc->dimensions;
image = doc->thumb;
} break;
case MediaTypePhoto: {
const auto media = item->media();
if (const auto photo = media->photo()) {
_photo = true;
auto photo = static_cast<HistoryPhoto*>(media.get())->getPhoto();
dimensions = QSize(photo->full->width(), photo->full->height());
image = photo->full;
} break;
case MediaTypeVideo: {
_animated = true;
doc = static_cast<HistoryVideo*>(media.get())->getDocument();
dimensions = doc->dimensions;
image = doc->thumb;
} break;
case MediaTypeGrouped: {
if (const auto photo = media->getPhoto()) {
dimensions = QSize(photo->full->width(), photo->full->height());
image = photo->full;
_photo = true;
} else if (const auto doc = media->getDocument()) {
dimensions = doc->dimensions;
image = doc->thumb;
} else if (const auto document = media->document()) {
dimensions = document->dimensions;
image = document->thumb;
if (document->isAnimation()) {
_animated = true;
} else if (document->isVideoFile()) {
_animated = true;
} else {
_doc = true;
}
} break;
case MediaTypeFile:
case MediaTypeMusicFile:
case MediaTypeVoiceFile: {
_doc = true;
doc = static_cast<HistoryDocument*>(media.get())->getDocument();
image = doc->thumb;
} break;
doc = document;
}
caption = media->getCaption().text;
auto caption = item->originalText().text;
if (!_animated && (dimensions.isEmpty() || doc || image->isNull())) {
if (image->isNull()) {

View File

@@ -9,13 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
namespace Data {
class Media;
} // namespace Data
namespace Ui {
class InputArea;
} // namespace Ui
class EditCaptionBox : public BoxContent, public RPCSender {
public:
EditCaptionBox(QWidget*, not_null<HistoryMedia*> media, FullMsgId msgId);
EditCaptionBox(QWidget*, not_null<HistoryItem*> item);
protected:
void prepare() override;

View File

@@ -415,7 +415,7 @@ MTPChannelBannedRights EditRestrictedBox::DefaultRights(not_null<ChannelData*> c
void EditRestrictedBox::showRestrictUntil() {
auto tomorrow = QDate::currentDate().addDays(1);
auto highlighted = isUntilForever() ? tomorrow : date(getRealUntilValue()).date();
auto highlighted = isUntilForever() ? tomorrow : ParseDateTime(getRealUntilValue()).date();
auto month = highlighted;
_restrictUntilBox = Ui::show(
Box<CalendarBox>(
@@ -469,9 +469,13 @@ void EditRestrictedBox::createUntilVariants() {
_untilVariants.back()->setDisabled(true);
}
};
auto addCustomVariant = [this, addVariant](TimeId until, TimeId from, TimeId to) {
auto addCustomVariant = [addVariant](TimeId until, TimeId from, TimeId to) {
if (!ChannelData::IsRestrictedForever(until) && until > from && until <= to) {
addVariant(until, lng_rights_chat_banned_custom_date(lt_date, langDayOfMonthFull(date(until).date())));
addVariant(
until,
lng_rights_chat_banned_custom_date(
lt_date,
langDayOfMonthFull(ParseDateTime(until).date())));
}
};
auto addCurrentVariant = [this, addCustomVariant](TimeId from, TimeId to) {

View File

@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
#include "ui/wrap/slide_wrap.h"
#include "history/history.h"
#include "boxes/peer_list_controllers.h"
#include "apiwrap.h"
#include "auth_session.h"
@@ -94,7 +95,7 @@ void EditPrivacyBox::prepare() {
int EditPrivacyBox::resizeGetHeight(int newWidth) {
auto top = 0;
auto layoutRow = [this, newWidth, &top](auto &widget, style::margins padding) {
auto layoutRow = [&](auto &widget, style::margins padding) {
if (!widget) return;
widget->resizeToNaturalWidth(newWidth - padding.left() - padding.right());
widget->moveToLeft(padding.left(), top + padding.top());
@@ -136,7 +137,7 @@ int EditPrivacyBox::countDefaultHeight(int newWidth) {
}
return st::editPrivacyOptionMargin.top() + st::defaultCheck.diameter + st::editPrivacyOptionMargin.bottom();
};
auto labelHeight = [this, newWidth](const QString &text, const style::FlatLabel &st, style::margins padding) {
auto labelHeight = [newWidth](const QString &text, const style::FlatLabel &st, style::margins padding) {
if (text.isEmpty()) {
return 0;
}

View File

@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "auth_session.h"
#include "layout.h"
LocalStorageBox::LocalStorageBox(QWidget *parent)
: _clear(this, lang(lng_local_storage_clear), st::boxLinkButton) {

View File

@@ -250,6 +250,11 @@ void PeerListController::setSearchNoResultsText(const QString &text) {
}
}
base::unique_qptr<Ui::PopupMenu> PeerListController::rowContextMenu(
not_null<PeerListRow*> row) {
return nullptr;
}
std::unique_ptr<PeerListState> PeerListController::saveState() const {
return delegate()->peerListSaveState();
}
@@ -563,6 +568,7 @@ PeerListContent::PeerListContent(
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());
@@ -573,6 +579,7 @@ void PeerListContent::appendRow(std::unique_ptr<PeerListRow> row) {
void PeerListContent::appendSearchRow(std::unique_ptr<PeerListRow> row) {
Expects(row != nullptr);
Expects(showingSearch());
if (_rowsById.find(row->id()) == _rowsById.cend()) {
row->setAbsoluteIndex(_searchRows.size());
row->setIsSearchResult(true);
@@ -584,13 +591,17 @@ void PeerListContent::appendSearchRow(std::unique_ptr<PeerListRow> row) {
void PeerListContent::appendFoundRow(not_null<PeerListRow*> row) {
Expects(showingSearch());
auto index = findRowIndex(row);
if (index.value < 0) {
_filterResults.push_back(row);
}
}
void PeerListContent::changeCheckState(not_null<PeerListRow*> row, bool checked, PeerListRow::SetStyle style) {
void PeerListContent::changeCheckState(
not_null<PeerListRow*> row,
bool checked,
PeerListRow::SetStyle style) {
row->setChecked(
checked,
style,
@@ -629,16 +640,16 @@ void PeerListContent::addToSearchIndex(not_null<PeerListRow*> row) {
}
removeFromSearchIndex(row);
row->setNameFirstChars(row->peer()->nameFirstChars());
for (auto ch : row->nameFirstChars()) {
row->setNameFirstLetters(row->peer()->nameFirstLetters());
for (auto ch : row->nameFirstLetters()) {
_searchIndex[ch].push_back(row);
}
}
void PeerListContent::removeFromSearchIndex(not_null<PeerListRow*> row) {
auto &nameFirstChars = row->nameFirstChars();
if (!nameFirstChars.empty()) {
for (auto ch : row->nameFirstChars()) {
const auto &nameFirstLetters = row->nameFirstLetters();
if (!nameFirstLetters.empty()) {
for (auto ch : row->nameFirstLetters()) {
auto it = _searchIndex.find(ch);
if (it != _searchIndex.cend()) {
auto &entry = it->second;
@@ -648,7 +659,7 @@ void PeerListContent::removeFromSearchIndex(not_null<PeerListRow*> row) {
}
}
}
row->setNameFirstChars({});
row->setNameFirstLetters({});
}
}
@@ -1008,7 +1019,7 @@ void PeerListContent::contextMenuEvent(QContextMenuEvent *e) {
mousePressReleased(_pressButton);
}
if (auto row = getRow(_contexted.index)) {
if (const auto row = getRow(_contexted.index)) {
_contextMenu = _controller->rowContextMenu(row);
if (_contextMenu) {
_contextMenu->setDestroyedCallback(base::lambda_guarded(

View File

@@ -177,11 +177,11 @@ public:
int outerWidth);
float64 checkedRatio();
void setNameFirstChars(const base::flat_set<QChar> &nameFirstChars) {
_nameFirstChars = nameFirstChars;
void setNameFirstLetters(const base::flat_set<QChar> &firstLetters) {
_nameFirstLetters = firstLetters;
}
const base::flat_set<QChar> &nameFirstChars() const {
return _nameFirstChars;
const base::flat_set<QChar> &nameFirstLetters() const {
return _nameFirstLetters;
}
virtual void lazyInitialize(const style::PeerListItem &st);
@@ -218,7 +218,7 @@ private:
Text _status;
StatusType _statusType = StatusType::Online;
TimeMs _statusValidTill = 0;
base::flat_set<QChar> _nameFirstChars;
base::flat_set<QChar> _nameFirstLetters;
int _absoluteIndex = -1;
State _disabledState = State::Active;
bool _initialized : 1;
@@ -344,10 +344,8 @@ public:
}
virtual void itemDeselectedHook(not_null<PeerData*> peer) {
}
virtual Ui::PopupMenu *rowContextMenu(
not_null<PeerListRow*> row) {
return nullptr;
}
virtual base::unique_qptr<Ui::PopupMenu> rowContextMenu(
not_null<PeerListRow*> row);
bool isSearchLoading() const {
return _searchController ? _searchController->isLoading() : false;
}
@@ -360,7 +358,7 @@ public:
return nullptr;
}
virtual std::unique_ptr<PeerListState> saveState() const ;
virtual std::unique_ptr<PeerListState> saveState() const;
virtual void restoreState(
std::unique_ptr<PeerListState> state);
@@ -625,7 +623,7 @@ private:
std::vector<std::unique_ptr<PeerListRow>> _searchRows;
base::Timer _repaintByStatus;
QPointer<Ui::PopupMenu> _contextMenu;
base::unique_qptr<Ui::PopupMenu> _contextMenu;
};

View File

@@ -13,9 +13,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "observer_peer.h"
#include "ui/widgets/checkbox.h"
#include "auth_session.h"
#include "data/data_session.h"
#include "apiwrap.h"
#include "mainwidget.h"
#include "lang/lang_keys.h"
#include "history/history.h"
#include "dialogs/dialogs_indexed_list.h"
namespace {
@@ -147,7 +149,7 @@ void PeerListGlobalSearchController::searchQuery(const QString &query) {
if (_query != query) {
_query = query;
_requestId = 0;
if (_query.size() >= MinUsernameLength && !searchInCache()) {
if (!_query.isEmpty() && !searchInCache()) {
_timer.callOnce(AutoSearchTimeout);
} else {
_timer.cancel();
@@ -166,9 +168,12 @@ bool PeerListGlobalSearchController::searchInCache() {
}
void PeerListGlobalSearchController::searchOnServer() {
_requestId = request(MTPcontacts_Search(MTP_string(_query), MTP_int(SearchPeopleLimit))).done([this](const MTPcontacts_Found &result, mtpRequestId requestId) {
_requestId = request(MTPcontacts_Search(
MTP_string(_query),
MTP_int(SearchPeopleLimit)
)).done([=](const MTPcontacts_Found &result, mtpRequestId requestId) {
searchDone(result, requestId);
}).fail([this](const RPCError &error, mtpRequestId requestId) {
}).fail([=](const RPCError &error, mtpRequestId requestId) {
if (_requestId == requestId) {
_requestId = 0;
delegate()->peerListSearchRefreshRows();
@@ -177,7 +182,9 @@ void PeerListGlobalSearchController::searchOnServer() {
_queries.emplace(_requestId, _query);
}
void PeerListGlobalSearchController::searchDone(const MTPcontacts_Found &result, mtpRequestId requestId) {
void PeerListGlobalSearchController::searchDone(
const MTPcontacts_Found &result,
mtpRequestId requestId) {
Expects(result.type() == mtpc_contacts_found);
auto &contacts = result.c_contacts_found();
@@ -192,13 +199,17 @@ void PeerListGlobalSearchController::searchDone(const MTPcontacts_Found &result,
_queries.erase(it);
}
}
if (_requestId == requestId) {
_requestId = 0;
for_const (auto &mtpPeer, contacts.vresults.v) {
if (auto peer = App::peerLoaded(peerFromMTP(mtpPeer))) {
const auto feedList = [&](const MTPVector<MTPPeer> &list) {
for (const auto &mtpPeer : list.v) {
if (const auto peer = App::peerLoaded(peerFromMTP(mtpPeer))) {
delegate()->peerListSearchAddRow(peer);
}
}
};
if (_requestId == requestId) {
_requestId = 0;
feedList(contacts.vmy_results);
feedList(contacts.vresults);
delegate()->peerListSearchRefreshRows();
}
}
@@ -207,6 +218,11 @@ bool PeerListGlobalSearchController::isLoading() {
return _timer.isActive() || _requestId;
}
ChatsListBoxController::Row::Row(not_null<History*> history)
: PeerListRow(history->peer)
, _history(history) {
}
ChatsListBoxController::ChatsListBoxController(
std::unique_ptr<PeerListSearchController> searchController)
: PeerListController(std::move(searchController)) {
@@ -236,9 +252,11 @@ void ChatsListBoxController::rebuildRows() {
auto wasEmpty = !delegate()->peerListFullRowsCount();
auto appendList = [this](auto chats) {
auto count = 0;
for_const (auto row, chats->all()) {
if (appendRow(row->history())) {
++count;
for (const auto row : chats->all()) {
if (const auto history = row->history()) {
if (appendRow(history)) {
++count;
}
}
}
return count;
@@ -320,11 +338,12 @@ void ContactsBoxController::prepare() {
void ContactsBoxController::rebuildRows() {
auto appendList = [this](auto chats) {
auto count = 0;
for_const (auto row, chats->all()) {
auto history = row->history();
if (auto user = history->peer->asUser()) {
if (appendRow(user)) {
++count;
for (const auto row : chats->all()) {
if (const auto history = row->history()) {
if (const auto user = history->peer->asUser()) {
if (appendRow(user)) {
++count;
}
}
}
}
@@ -345,8 +364,9 @@ void ContactsBoxController::checkForEmptyRows() {
}
}
std::unique_ptr<PeerListRow> ContactsBoxController::createSearchRow(not_null<PeerData*> peer) {
if (auto user = peer->asUser()) {
std::unique_ptr<PeerListRow> ContactsBoxController::createSearchRow(
not_null<PeerData*> peer) {
if (const auto user = peer->asUser()) {
return createRow(user);
}
return nullptr;
@@ -711,7 +731,7 @@ void EditChatAdminsBoxController::Start(not_null<ChatData*> chat) {
}
void AddBotToGroupBoxController::Start(not_null<UserData*> bot) {
auto initBox = [bot](not_null<PeerListBox*> box) {
auto initBox = [=](not_null<PeerListBox*> box) {
box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); });
};
Ui::show(Box<PeerListBox>(std::make_unique<AddBotToGroupBoxController>(bot), std::move(initBox)));
@@ -748,8 +768,10 @@ void AddBotToGroupBoxController::shareBotGame(not_null<PeerData*> chat) {
MTP_inputGameShortName(
bot->inputUser,
MTP_string(bot->botInfo->shareGameShortName))),
MTP_string(""),
MTP_long(randomId),
MTPnullMarkup),
MTPnullMarkup,
MTPnullEntities),
App::main()->rpcDone(&MainWidget::sentUpdatesReceived),
App::main()->rpcFail(&MainWidget::sendMessageFail),
0,

View File

@@ -91,8 +91,8 @@ public:
protected:
class Row : public PeerListRow {
public:
Row(not_null<History*> history) : PeerListRow(history->peer), _history(history) {
}
Row(not_null<History*> history);
not_null<History*> history() const {
return _history;
}

View File

@@ -37,6 +37,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kUsernameCheckTimeout = TimeMs(200);
constexpr auto kMinUsernameLength = 5;
constexpr auto kMaxChannelDescription = 255; // See also add_contact_box.
class Controller
: private MTP::Sender
@@ -323,6 +325,7 @@ object_ptr<Ui::RpWidget> Controller::createDescriptionEdit() {
langFactory(lng_create_group_description),
channel->about()),
st::editPeerDescriptionMargins);
result->entity()->setMaxLength(kMaxChannelDescription);
QObject::connect(
result->entity(),
@@ -503,7 +506,7 @@ void Controller::checkUsernameAvailability() {
auto checking = initial
? qsl(".bad.")
: _controls.username->getLastText().trimmed();
if (checking.size() < MinUsernameLength) {
if (checking.size() < kMinUsernameLength) {
return;
}
if (_checkUsernameRequestId) {
@@ -580,7 +583,7 @@ void Controller::usernameChanged() {
if (bad) {
showUsernameError(
Lang::Viewer(lng_create_channel_link_bad_symbols));
} else if (username.size() < MinUsernameLength) {
} else if (username.size() < kMinUsernameLength) {
showUsernameError(
Lang::Viewer(lng_create_channel_link_too_short));
} else {
@@ -1251,11 +1254,9 @@ void Controller::saveTitle() {
continueSave();
return;
}
_controls.title->showError();
if (type == qstr("NO_CHAT_TITLE")) {
_controls.title->showError();
_box->scrollToWidget(_controls.title);
} else {
_controls.title->setFocus();
}
cancelSave();
};
@@ -1301,7 +1302,7 @@ void Controller::saveDescription() {
successCallback();
return;
}
_controls.description->setFocus();
_controls.description->showError();
cancelSave();
}).send();
}

View File

@@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_peer_info_box.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/widgets/labels.h"
#include "history/history_admin_log_section.h"
#include "history/admin_log/history_admin_log_section.h"
#include "window/window_controller.h"
#include "profile/profile_channel_controllers.h"
#include "info/profile/info_profile_button.h"

View File

@@ -14,23 +14,54 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/toast/toast.h"
#include "mainwindow.h"
ReportBox::ReportBox(QWidget*, PeerData *peer) : _peer(peer)
, _reasonGroup(std::make_shared<Ui::RadioenumGroup<Reason>>(Reason::Spam))
, _reasonSpam(this, _reasonGroup, Reason::Spam, lang(lng_report_reason_spam), st::defaultBoxCheckbox)
, _reasonViolence(this, _reasonGroup, Reason::Violence, lang(lng_report_reason_violence), st::defaultBoxCheckbox)
, _reasonPornography(this, _reasonGroup, Reason::Pornography, lang(lng_report_reason_pornography), st::defaultBoxCheckbox)
, _reasonOther(this, _reasonGroup, Reason::Other, lang(lng_report_reason_other), st::defaultBoxCheckbox) {
ReportBox::ReportBox(QWidget*, not_null<PeerData*> peer)
: _peer(peer) {
}
ReportBox::ReportBox(QWidget*, not_null<PeerData*> peer, MessageIdsList ids)
: _peer(peer)
, _ids(std::move(ids)) {
}
void ReportBox::prepare() {
setTitle(langFactory(_peer->isUser() ? lng_report_bot_title : (_peer->isMegagroup() ? lng_report_group_title : lng_report_title)));
setTitle(langFactory([&] {
if (_ids) {
return lng_report_message_title;
} else if (_peer->isUser()) {
return lng_report_bot_title;
} else if (_peer->isMegagroup()) {
return lng_report_group_title;
} else {
return lng_report_title;
}
}()));
addButton(langFactory(lng_report_button), [this] { onReport(); });
addButton(langFactory(lng_cancel), [this] { closeBox(); });
_reasonGroup->setChangedCallback([this](Reason value) { reasonChanged(value); });
_reasonGroup = std::make_shared<Ui::RadioenumGroup<Reason>>(
Reason::Spam);
const auto createButton = [&](
object_ptr<Ui::Radioenum<Reason>> &button,
Reason reason,
LangKey key) {
button.create(
this,
_reasonGroup,
reason,
lang(key),
st::defaultBoxCheckbox);
};
createButton(_reasonSpam, Reason::Spam, lng_report_reason_spam);
createButton(_reasonViolence, Reason::Violence, lng_report_reason_violence);
createButton(_reasonPornography, Reason::Pornography, lng_report_reason_pornography);
createButton(_reasonOther, Reason::Other, lng_report_reason_other);
_reasonGroup->setChangedCallback([=](Reason value) {
reasonChanged(value);
});
updateMaxHeight();
}
@@ -90,7 +121,7 @@ void ReportBox::onReport() {
return;
}
auto getReason = [this]() {
const auto reason = [&] {
switch (_reasonGroup->value()) {
case Reason::Spam: return MTP_inputReportReasonSpam();
case Reason::Violence: return MTP_inputReportReasonViolence();
@@ -98,17 +129,37 @@ void ReportBox::onReport() {
case Reason::Other: return MTP_inputReportReasonOther(MTP_string(_reasonOtherText->getLastText()));
}
Unexpected("Bad reason group value.");
};
_requestId = MTP::send(MTPaccount_ReportPeer(_peer->input, getReason()), rpcDone(&ReportBox::reportDone), rpcFail(&ReportBox::reportFail));
}();
if (_ids) {
auto ids = QVector<MTPint>();
for (const auto &fullId : *_ids) {
ids.push_back(MTP_int(fullId.msg));
}
_requestId = MTP::send(
MTPmessages_Report(
_peer->input,
MTP_vector<MTPint>(ids),
reason),
rpcDone(&ReportBox::reportDone),
rpcFail(&ReportBox::reportFail));
} else {
_requestId = MTP::send(
MTPaccount_ReportPeer(_peer->input, reason),
rpcDone(&ReportBox::reportDone),
rpcFail(&ReportBox::reportFail));
}
}
void ReportBox::reportDone(const MTPBool &result) {
_requestId = 0;
Ui::show(Box<InformBox>(lang(lng_report_thanks)));
Ui::Toast::Show(lang(lng_report_thanks));
closeBox();
}
bool ReportBox::reportFail(const RPCError &error) {
if (MTP::isDefaultHandledError(error)) return false;
if (MTP::isDefaultHandledError(error)) {
return false;
}
_requestId = 0;
if (_reasonOtherText) {

View File

@@ -21,7 +21,8 @@ class ReportBox : public BoxContent, public RPCSender {
Q_OBJECT
public:
ReportBox(QWidget*, PeerData *peer);
ReportBox(QWidget*, not_null<PeerData*> peer);
ReportBox(QWidget*, not_null<PeerData*> peer, MessageIdsList ids);
private slots:
void onReport();
@@ -49,13 +50,14 @@ private:
void reportDone(const MTPBool &result);
bool reportFail(const RPCError &error);
PeerData *_peer;
not_null<PeerData*> _peer;
base::optional<MessageIdsList> _ids;
std::shared_ptr<Ui::RadioenumGroup<Reason>> _reasonGroup;
object_ptr<Ui::Radioenum<Reason>> _reasonSpam;
object_ptr<Ui::Radioenum<Reason>> _reasonViolence;
object_ptr<Ui::Radioenum<Reason>> _reasonPornography;
object_ptr<Ui::Radioenum<Reason>> _reasonOther;
object_ptr<Ui::Radioenum<Reason>> _reasonSpam = { nullptr };
object_ptr<Ui::Radioenum<Reason>> _reasonViolence = { nullptr };
object_ptr<Ui::Radioenum<Reason>> _reasonPornography = { nullptr };
object_ptr<Ui::Radioenum<Reason>> _reasonOther = { nullptr };
object_ptr<Ui::InputArea> _reasonOtherText = { nullptr };
mtpRequestId _requestId = 0;

View File

@@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_controller.h"
#include "styles/style_history.h"
#include "styles/style_boxes.h"
#include "layout.h"
namespace {
@@ -783,7 +784,11 @@ void SingleFilePreview::preparePreview(const Storage::PreparedFile &file) {
prepareThumb(preview);
const auto filepath = file.path;
if (filepath.isEmpty()) {
auto filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
auto filename = filedialogDefaultName(
qsl("image"),
qsl(".png"),
QString(),
true);
_nameText.setText(
st::semiboldTextStyle,
filename,
@@ -1433,7 +1438,7 @@ void SendFilesBox::initSendWay() {
? SendFilesWay::Album
: SendFilesWay::Photos;
}
const auto currentWay = Auth().data().sendFilesWay();
const auto currentWay = Auth().settings().sendFilesWay();
if (currentWay == SendFilesWay::Files) {
return currentWay;
} else if (currentWay == SendFilesWay::Album) {
@@ -1576,18 +1581,21 @@ void SendFilesBox::captionResized() {
update();
}
bool SendFilesBox::canAddUrls(const QList<QUrl> &urls) const {
return !urls.isEmpty() && ranges::find_if(
urls,
[](const QUrl &url) { return !url.isLocalFile(); }
) == urls.end();
}
bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const {
auto files = 0;
if (data->hasUrls()) {
for (const auto &url : data->urls()) {
if (url.isLocalFile()) {
++files;
}
}
} else if (data->hasImage()) {
++files;
const auto urls = data->hasUrls() ? data->urls() : QList<QUrl>();
auto filesCount = canAddUrls(urls) ? urls.size() : 0;
if (!filesCount && data->hasImage()) {
++filesCount;
}
if (_list.files.size() + files > Storage::MaxAlbumItems()) {
if (_list.files.size() + filesCount > Storage::MaxAlbumItems()) {
return false;
} else if (_list.files.size() > 1 && !_albumPreview) {
return false;
@@ -1600,10 +1608,14 @@ bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const {
bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
auto list = [&] {
if (data->hasUrls()) {
return Storage::PrepareMediaList(
data->urls(),
st::sendMediaPreviewSize);
const auto urls = data->hasUrls() ? data->urls() : QList<QUrl>();
auto result = canAddUrls(urls)
? Storage::PrepareMediaList(urls, st::sendMediaPreviewSize)
: Storage::PreparedList(
Storage::PreparedList::Error::EmptyFile,
QString());
if (result.error == Storage::PreparedList::Error::None) {
return result;
} else if (data->hasImage()) {
auto image = qvariant_cast<QImage>(data->imageData());
if (!image.isNull()) {
@@ -1613,9 +1625,7 @@ bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
st::sendMediaPreviewSize);
}
}
return Storage::PreparedList(
Storage::PreparedList::Error::EmptyFile,
QString());
return result;
}();
if (_list.files.size() + list.files.size() > Storage::MaxAlbumItems()) {
return false;
@@ -1756,7 +1766,7 @@ void SendFilesBox::send(bool ctrlShiftEnter) {
const auto way = _sendWay ? _sendWay->value() : Way::Files;
if (_compressConfirm == CompressConfirm::Auto) {
const auto oldWay = Auth().data().sendFilesWay();
const auto oldWay = Auth().settings().sendFilesWay();
if (way != oldWay) {
// Check if the user _could_ use the old value, but didn't.
if ((oldWay == Way::Album && _sendAlbum)
@@ -1764,8 +1774,8 @@ void SendFilesBox::send(bool ctrlShiftEnter) {
|| (oldWay == Way::Files && _sendFiles)
|| (way == Way::Files && (_sendAlbum || _sendPhotos))) {
// And in that case save it to settings.
Auth().data().setSendFilesWay(way);
Auth().saveDataDelayed();
Auth().settings().setSendFilesWay(way);
Auth().saveSettingsDelayed();
}
}
}

View File

@@ -84,6 +84,7 @@ private:
void updateControlsGeometry();
bool canAddFiles(not_null<const QMimeData*> data) const;
bool canAddUrls(const QList<QUrl> &urls) const;
bool addFiles(not_null<const QMimeData*> data);
QString _titleText;

View File

@@ -119,8 +119,9 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) {
//CountriesByISO2::const_iterator j = countries.constFind(country);
//if (j != countries.cend()) country = QString::fromUtf8(j.value()->name);
MTPint active = d.vdate_active.v ? d.vdate_active : d.vdate_created;
data.activeTime = active.v;
const auto active = data.activeTime = d.vdate_active.v
? d.vdate_active.v
: d.vdate_created.v;
data.info = qs(d.vdevice_model) + qstr(", ") + (platform.isEmpty() ? QString() : platform + ' ') + qs(d.vsystem_version);
data.ip = qs(d.vip) + (country.isEmpty() ? QString() : QString::fromUtf8(" \xe2\x80\x93 ") + country);
@@ -144,12 +145,15 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) {
}
_current = data;
} else {
QDateTime now(QDateTime::currentDateTime()), lastTime(date(active));
QDate nowDate(now.date()), lastDate(lastTime.date());
const auto now = QDateTime::currentDateTime();
const auto lastTime = ParseDateTime(active);
const auto nowDate = now.date();
const auto lastDate = lastTime.date();
QString dt;
if (lastDate == nowDate) {
data.active = lastTime.toString(cTimeFormat());
} else if (lastDate.year() == nowDate.year() && lastDate.weekNumber() == nowDate.weekNumber()) {
} else if (lastDate.year() == nowDate.year()
&& lastDate.weekNumber() == nowDate.weekNumber()) {
data.active = langDayOfWeek(lastDate);
} else {
data.active = lastDate.toString(qsl("d.MM.yy"));

View File

@@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/scroll_area.h"
#include "ui/text_options.h"
#include "history/history.h"
#include "history/history_media_types.h"
#include "history/history_message.h"
#include "window/themes/window_theme.h"
@@ -92,7 +93,7 @@ bool ShareBox::onSearchByUsername(bool searchCache) {
}
return true;
}
if (query.size() >= MinUsernameLength) {
if (!query.isEmpty()) {
if (searchCache) {
auto i = _peopleCache.constFind(query);
if (i != _peopleCache.cend()) {
@@ -104,7 +105,12 @@ bool ShareBox::onSearchByUsername(bool searchCache) {
} else if (_peopleQuery != query) {
_peopleQuery = query;
_peopleFull = false;
_peopleRequest = MTP::send(MTPcontacts_Search(MTP_string(_peopleQuery), MTP_int(SearchPeopleLimit)), rpcDone(&ShareBox::peopleReceived), rpcFail(&ShareBox::peopleFailed));
_peopleRequest = MTP::send(
MTPcontacts_Search(
MTP_string(_peopleQuery),
MTP_int(SearchPeopleLimit)),
rpcDone(&ShareBox::peopleReceived),
rpcFail(&ShareBox::peopleFailed));
_peopleQueries.insert(_peopleRequest, _peopleQuery);
}
}
@@ -117,7 +123,11 @@ void ShareBox::onNeedSearchByUsername() {
}
}
void ShareBox::peopleReceived(const MTPcontacts_Found &result, mtpRequestId requestId) {
void ShareBox::peopleReceived(
const MTPcontacts_Found &result,
mtpRequestId requestId) {
Expects(result.type() == mtpc_contacts_found);
auto query = _peopleQuery;
auto i = _peopleQueries.find(requestId);
@@ -133,7 +143,10 @@ void ShareBox::peopleReceived(const MTPcontacts_Found &result, mtpRequestId requ
auto &found = result.c_contacts_found();
App::feedUsers(found.vusers);
App::feedChats(found.vchats);
_inner->peopleReceived(query, found.vresults.v);
_inner->peopleReceived(
query,
found.vmy_results.v,
found.vresults.v);
} break;
}
@@ -273,16 +286,18 @@ ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallbac
_rowHeight = st::shareRowHeight;
setAttribute(Qt::WA_OpaquePaintEvent);
auto dialogs = App::main()->dialogsList();
if (auto self = App::self()) {
const auto dialogs = App::main()->dialogsList();
if (const auto self = App::self()) {
if (_filterCallback(App::self())) {
_chatsIndexed->addToEnd(App::history(self));
}
}
for_const (auto row, dialogs->all()) {
auto history = row->history();
if (!history->peer->isSelf() && _filterCallback(history->peer)) {
_chatsIndexed->addToEnd(history);
for (const auto row : dialogs->all()) {
if (const auto history = row->history()) {
if (!history->peer->isSelf()
&& _filterCallback(history->peer)) {
_chatsIndexed->addToEnd(history);
}
}
}
@@ -347,7 +362,9 @@ void ShareBox::Inner::activateSkipPage(int pageHeight, int direction) {
void ShareBox::Inner::notifyPeerUpdated(const Notify::PeerUpdate &update) {
if (update.flags & Notify::PeerUpdate::Flag::NameChanged) {
_chatsIndexed->peerNameChanged(update.peer, update.oldNameFirstChars);
_chatsIndexed->peerNameChanged(
update.peer,
update.oldNameFirstLetters);
}
updateChat(update.peer);
@@ -402,20 +419,24 @@ void ShareBox::Inner::repaintChat(not_null<PeerData*> peer) {
int ShareBox::Inner::chatIndex(not_null<PeerData*> peer) const {
int index = 0;
if (_filter.isEmpty()) {
for_const (auto row, _chatsIndexed->all()) {
if (row->history()->peer == peer) {
return index;
for (const auto row : _chatsIndexed->all()) {
if (const auto history = row->history()) {
if (history->peer == peer) {
return index;
}
}
++index;
}
} else {
for_const (auto row, _filtered) {
if (row->history()->peer == peer) {
return index;
for (const auto row : _filtered) {
if (const auto history = row->history()) {
if (history->peer == peer) {
return index;
}
}
++index;
}
for_const (auto row, d_byUsernameFiltered) {
for (const auto row : d_byUsernameFiltered) {
if (row->peer == peer) {
return index;
}
@@ -448,7 +469,7 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) {
if (((*i)->pos() * _rowHeight) >= yTo) {
break;
}
(*i)->history()->peer->loadUserpic();
(*i)->entry()->loadUserpic();
}
}
} else if (!_filtered.isEmpty()) {
@@ -459,13 +480,15 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) {
if (to > _filtered.size()) to = _filtered.size();
for (; from < to; ++from) {
_filtered[from]->history()->peer->loadUserpic();
_filtered[from]->entry()->loadUserpic();
}
}
}
}
ShareBox::Inner::Chat *ShareBox::Inner::getChat(Dialogs::Row *row) {
Expects(row->history() != nullptr);
auto data = static_cast<Chat*>(row->attached);
if (!data) {
auto peer = row->history()->peer;
@@ -550,15 +573,23 @@ void ShareBox::Inner::paintEvent(QPaintEvent *e) {
++indexFrom;
}
} else {
// empty
p.setFont(st::noContactsFont);
p.setPen(st::noContactsColor);
p.drawText(
rect().marginsRemoved(st::boxPadding),
lang(lng_bot_no_chats),
style::al_center);
}
} else {
if (_filtered.isEmpty() && _byUsernameFiltered.isEmpty()) {
// empty
if (_filtered.isEmpty()
&& _byUsernameFiltered.empty()
&& !_searching) {
p.setFont(st::noContactsFont);
p.setPen(st::noContactsColor);
p.drawText(
rect().marginsRemoved(st::boxPadding),
lang(lng_bot_chats_not_found),
style::al_center);
} else {
auto filteredSize = _filtered.size();
if (filteredSize) {
@@ -573,7 +604,7 @@ void ShareBox::Inner::paintEvent(QPaintEvent *e) {
indexFrom -= filteredSize;
indexTo -= filteredSize;
}
if (!_byUsernameFiltered.isEmpty()) {
if (!_byUsernameFiltered.empty()) {
if (indexFrom < 0) indexFrom = 0;
while (indexFrom < indexTo) {
if (indexFrom >= d_byUsernameFiltered.size()) {
@@ -638,16 +669,17 @@ void ShareBox::Inner::changeCheckState(Chat *chat) {
if (!chat) return;
if (!_filter.isEmpty()) {
auto row = _chatsIndexed->getRow(chat->peer->id);
const auto history = App::history(chat->peer);
auto row = _chatsIndexed->getRow(history);
if (!row) {
auto rowsByLetter = _chatsIndexed->addToEnd(App::history(chat->peer));
auto it = rowsByLetter.find(0);
const auto rowsByLetter = _chatsIndexed->addToEnd(history);
const auto it = rowsByLetter.find(0);
Assert(it != rowsByLetter.cend());
row = it->second;
}
chat = getChat(row);
if (!chat->checkbox.checked()) {
_chatsIndexed->moveToTop(chat->peer);
_chatsIndexed->moveToTop(history);
}
}
@@ -721,8 +753,8 @@ void ShareBox::Inner::updateFilter(QString filter) {
}
if (toFilter) {
_filtered.reserve(toFilter->size());
for_const (auto row, *toFilter) {
auto &nameWords = row->history()->peer->nameWords();
for (const auto row : *toFilter) {
auto &nameWords = row->entry()->chatsListNameWords();
auto nb = nameWords.cbegin(), ne = nameWords.cend(), ni = nb;
for (fi = fb; fi != fe; ++fi) {
auto filterName = *fi;
@@ -752,32 +784,38 @@ void ShareBox::Inner::updateFilter(QString filter) {
}
}
void ShareBox::Inner::peopleReceived(const QString &query, const QVector<MTPPeer> &people) {
void ShareBox::Inner::peopleReceived(
const QString &query,
const QVector<MTPPeer> &my,
const QVector<MTPPeer> &people) {
_lastQuery = query.toLower().trimmed();
if (_lastQuery.at(0) == '@') _lastQuery = _lastQuery.mid(1);
int32 already = _byUsernameFiltered.size();
_byUsernameFiltered.reserve(already + people.size());
d_byUsernameFiltered.reserve(already + people.size());
for_const (auto &mtpPeer, people) {
auto peerId = peerFromMTP(mtpPeer);
int j = 0;
for (; j < already; ++j) {
if (_byUsernameFiltered[j]->id == peerId) break;
}
if (j == already) {
auto *peer = App::peer(peerId);
if (!peer || !_filterCallback(peer)) continue;
auto chat = new Chat(peer, [this, peer] { repaintChat(peer); });
updateChatName(chat, peer);
if (auto row = _chatsIndexed->getRow(peer->id)) {
continue;
}
_byUsernameFiltered.push_back(peer);
d_byUsernameFiltered.push_back(chat);
}
if (_lastQuery.at(0) == '@') {
_lastQuery = _lastQuery.mid(1);
}
int32 already = _byUsernameFiltered.size();
_byUsernameFiltered.reserve(already + my.size() + people.size());
d_byUsernameFiltered.reserve(already + my.size() + people.size());
const auto feedList = [&](const QVector<MTPPeer> &list) {
for (const auto &mtpPeer : list) {
if (const auto peer = App::peerLoaded(peerFromMTP(mtpPeer))) {
const auto history = App::historyLoaded(peer);
if (!_filterCallback(peer)) {
continue;
} else if (history && _chatsIndexed->getRow(history)) {
continue;
} else if (base::contains(_byUsernameFiltered, peer)) {
continue;
}
auto chat = new Chat(peer, [=] { repaintChat(peer); });
updateChatName(chat, peer);
_byUsernameFiltered.push_back(peer);
d_byUsernameFiltered.push_back(chat);
}
}
};
feedList(my);
feedList(people);
_searching = false;
refresh();
}

View File

@@ -65,7 +65,9 @@ private:
void addPeerToMultiSelect(PeerData *peer, bool skipAnimation = false);
void onPeerSelectedChanged(PeerData *peer, bool checked);
void peopleReceived(const MTPcontacts_Found &result, mtpRequestId requestId);
void peopleReceived(
const MTPcontacts_Found &result,
mtpRequestId requestId);
bool peopleFailed(const RPCError &error, mtpRequestId requestId);
CopyCallback _copyCallback;
@@ -107,7 +109,10 @@ public:
QVector<PeerData*> selected() const;
bool hasSelected() const;
void peopleReceived(const QString &query, const QVector<MTPPeer> &people);
void peopleReceived(
const QString &query,
const QVector<MTPPeer> &my,
const QVector<MTPPeer> &people);
void activateSkipRow(int direction);
void activateSkipColumn(int direction);
@@ -202,9 +207,7 @@ private:
bool _searching = false;
QString _lastQuery;
using ByUsernameRows = QVector<PeerData*>;
using ByUsernameDatas = QVector<Chat*>;
ByUsernameRows _byUsernameFiltered;
ByUsernameDatas d_byUsernameFiltered;
std::vector<PeerData*> _byUsernameFiltered;
std::vector<Chat*> d_byUsernameFiltered;
};

View File

@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/sticker_set_box.h"
#include "data/data_document.h"
#include "data/data_session.h"
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "mainwindow.h"
@@ -121,8 +122,8 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
_pack.reserve(v.size());
_packOvers.reserve(v.size());
for (int i = 0, l = v.size(); i < l; ++i) {
auto doc = App::feedDocument(v.at(i));
if (!doc || !doc->sticker()) continue;
auto doc = Auth().data().document(v.at(i));
if (!doc->sticker()) continue;
_pack.push_back(doc);
_packOvers.push_back(Animation());
@@ -138,7 +139,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
Stickers::Pack p;
p.reserve(stickers.size());
for (auto j = 0, c = stickers.size(); j != c; ++j) {
auto doc = App::document(stickers[j].v);
auto doc = Auth().data().document(stickers[j].v);
if (!doc || !doc->sticker()) continue;
p.push_back(doc);
@@ -155,12 +156,16 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
_setCount = s.vcount.v;
_setHash = s.vhash.v;
_setFlags = s.vflags.v;
_setInstallDate = s.has_installed_date()
? s.vinstalled_date.v
: TimeId(0);
auto &sets = Auth().data().stickerSetsRef();
auto it = sets.find(_setId);
if (it != sets.cend()) {
auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_special);
_setFlags |= clientFlags;
it->flags = _setFlags;
it->installDate = _setInstallDate;
it->stickers = _pack;
it->emoji = _emoji;
}
@@ -200,13 +205,25 @@ void StickerSetBox::Inner::installDone(const MTPmessages_StickerSetInstallResult
Auth().data().archivedStickerSetsOrderRef().removeAt(index);
}
}
_setInstallDate = unixtime();
_setFlags &= ~MTPDstickerSet::Flag::f_archived;
_setFlags |= MTPDstickerSet::Flag::f_installed;
_setFlags |= MTPDstickerSet::Flag::f_installed_date;
auto it = sets.find(_setId);
if (it == sets.cend()) {
it = sets.insert(_setId, Stickers::Set(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags));
it = sets.insert(
_setId,
Stickers::Set(
_setId,
_setAccess,
_setTitle,
_setShortName,
_setCount,
_setHash,
_setFlags,
_setInstallDate));
} else {
it->flags = _setFlags;
it->installDate = _setInstallDate;
}
it->stickers = _pack;
it->emoji = _emoji;
@@ -238,7 +255,7 @@ void StickerSetBox::Inner::installDone(const MTPmessages_StickerSetInstallResult
Local::writeArchivedStickers();
}
Local::writeInstalledStickers();
Auth().data().markStickersUpdated();
Auth().data().notifyStickersUpdated();
}
_setInstalled.fire_copy(_setId);
}
@@ -395,11 +412,17 @@ bool StickerSetBox::Inner::loaded() const {
return _loaded && !_pack.isEmpty();
}
int32 StickerSetBox::Inner::notInstalled() const {
if (!_loaded) return 0;
auto it = Auth().data().stickerSets().constFind(_setId);
if (it == Auth().data().stickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_installed) || (it->flags & MTPDstickerSet::Flag::f_archived)) return _pack.size();
return 0;
bool StickerSetBox::Inner::notInstalled() const {
if (!_loaded) {
return false;
}
const auto it = Auth().data().stickerSets().constFind(_setId);
if ((it == Auth().data().stickerSets().cend())
|| !(it->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->flags & MTPDstickerSet::Flag::f_archived)) {
return _pack.size() > 0;
}
return false;
}
bool StickerSetBox::Inner::official() const {

View File

@@ -50,7 +50,7 @@ public:
Inner(QWidget *parent, const MTPInputStickerSet &set);
bool loaded() const;
int32 notInstalled() const;
bool notInstalled() const;
bool official() const;
base::lambda<TextWithEntities()> title() const;
QString shortName() const;
@@ -98,9 +98,10 @@ private:
uint64 _setId = 0;
uint64 _setAccess = 0;
QString _setTitle, _setShortName;
int32 _setCount = 0;
int _setCount = 0;
int32 _setHash = 0;
MTPDstickerSet::Flags _setFlags = 0;
TimeId _setInstallDate = TimeId(0);
MTPInputStickerSet _input;

View File

@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "stickers_box.h"
#include "data/data_document.h"
#include "data/data_session.h"
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "chat_helpers/stickers.h"
@@ -162,8 +163,7 @@ void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedSti
auto addedSet = false;
auto changedSets = false;
auto &v = stickers.vsets.v;
for_const (auto &stickerSet, v) {
for_const (const auto &stickerSet, stickers.vsets.v) {
const MTPDstickerSet *setData = nullptr;
switch (stickerSet.type()) {
case mtpc_stickerSetCovered: {
@@ -201,7 +201,8 @@ void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedSti
if (addedSet) {
_archived.widget()->updateSize();
} else {
_allArchivedLoaded = v.isEmpty() || (!changedSets && offsetId != 0);
_allArchivedLoaded = stickers.vsets.v.isEmpty()
|| (!changedSets && offsetId != 0);
if (changedSets) {
loadMoreArchived();
}
@@ -445,8 +446,14 @@ void StickersBox::installSet(uint64 setId) {
if (_featured.widget()) _featured.widget()->setRemovedSets(_localRemoved);
_archived.widget()->setRemovedSets(_localRemoved);
}
if (!(it->flags & MTPDstickerSet::Flag::f_installed) || (it->flags & MTPDstickerSet::Flag::f_archived)) {
MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), rpcDone(&StickersBox::installDone), rpcFail(&StickersBox::installFail, setId));
if (!(it->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->flags & MTPDstickerSet::Flag::f_archived)) {
MTP::send(
MTPmessages_InstallStickerSet(
Stickers::inputSetId(*it),
MTP_boolFalse()),
rpcDone(&StickersBox::installDone),
rpcFail(&StickersBox::installFail, setId));
Stickers::InstallLocally(setId);
}
@@ -454,7 +461,8 @@ void StickersBox::installSet(uint64 setId) {
void StickersBox::installDone(const MTPmessages_StickerSetInstallResult &result) {
if (result.type() == mtpc_messages_stickerSetInstallResultArchive) {
Stickers::ApplyArchivedResult(result.c_messages_stickerSetInstallResultArchive());
Stickers::ApplyArchivedResult(
result.c_messages_stickerSetInstallResultArchive());
}
}
@@ -1563,8 +1571,13 @@ QString StickersBox::Inner::fillSetTitle(const Stickers::Set &set, int maxNameWi
return result;
}
void StickersBox::Inner::fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived) {
*outInstalled = (set.flags & MTPDstickerSet::Flag::f_installed);
void StickersBox::Inner::fillSetFlags(
const Stickers::Set &set,
bool *outInstalled,
bool *outOfficial,
bool *outUnread,
bool *outArchived) {
*outInstalled = (set.flags & MTPDstickerSet::Flag::f_installed_date);
*outOfficial = (set.flags & MTPDstickerSet::Flag::f_official);
*outArchived = (set.flags & MTPDstickerSet::Flag::f_archived);
if (_section == Section::Featured) {

View File

@@ -17,6 +17,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_boxes.h"
#include "messenger.h"
namespace {
constexpr auto kMinUsernameLength = 5;
} // namespace
UsernameBox::UsernameBox(QWidget*)
: _username(this, st::defaultInputField, [] { return qsl("@username"); }, App::self()->username, false)
, _link(this, QString(), st::boxLinkButton)
@@ -102,9 +108,13 @@ void UsernameBox::onCheck() {
MTP::cancel(_checkRequestId);
}
QString name = getName();
if (name.size() >= MinUsernameLength) {
if (name.size() >= kMinUsernameLength) {
_checkUsername = name;
_checkRequestId = MTP::send(MTPaccount_CheckUsername(MTP_string(name)), rpcDone(&UsernameBox::onCheckDone), rpcFail(&UsernameBox::onCheckFail));
_checkRequestId = MTP::send(
MTPaccount_CheckUsername(
MTP_string(name)),
rpcDone(&UsernameBox::onCheckDone),
rpcFail(&UsernameBox::onCheckFail));
}
}
@@ -130,7 +140,7 @@ void UsernameBox::onChanged() {
return;
}
}
if (name.size() < MinUsernameLength) {
if (name.size() < kMinUsernameLength) {
if (_errorText != lang(lng_username_too_short)) {
_errorText = lang(lng_username_too_short);
update();

View File

@@ -13,9 +13,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "observer_peer.h"
#include "ui/effects/ripple_animation.h"
#include "calls/calls_instance.h"
#include "history/history_media_types.h"
#include "history/history.h"
#include "history/history_item.h"
#include "mainwidget.h"
#include "auth_session.h"
#include "data/data_session.h"
#include "data/data_media_types.h"
namespace Calls {
namespace {
@@ -36,7 +39,8 @@ public:
};
bool canAddItem(not_null<const HistoryItem*> item) const {
return (ComputeType(item) == _type && item->date.date() == _date);
return (ComputeType(item) == _type)
&& (ItemDateTime(item).date() == _date);
}
void addItem(not_null<HistoryItem*> item) {
Expects(canAddItem(item));
@@ -114,7 +118,7 @@ private:
BoxController::Row::Row(not_null<HistoryItem*> item)
: PeerListRow(item->history()->peer, item->id)
, _items(1, item)
, _date(item->date.date())
, _date(ItemDateTime(item).date())
, _type(ComputeType(item)) {
refreshStatus();
}
@@ -159,7 +163,7 @@ void BoxController::Row::refreshStatus() {
return;
}
auto text = [this] {
auto time = _items.front()->date.time().toString(cTimeFormat());
auto time = ItemDateTime(_items.front()).time().toString(cTimeFormat());
auto today = QDateTime::currentDateTime().date();
if (_date == today) {
return lng_call_box_status_today(lt_time, time);
@@ -175,10 +179,11 @@ BoxController::Row::Type BoxController::Row::ComputeType(
not_null<const HistoryItem*> item) {
if (item->out()) {
return Type::Out;
} else if (auto media = item->getMedia()) {
if (media->type() == MediaTypeCall) {
auto reason = static_cast<HistoryCall*>(media)->reason();
if (reason == HistoryCall::FinishReason::Busy || reason == HistoryCall::FinishReason::Missed) {
} else if (auto media = item->media()) {
if (const auto call = media->call()) {
const auto reason = call->finishReason;
if (reason == Data::Call::FinishReason::Busy
|| reason == Data::Call::FinishReason::Missed) {
return Type::Missed;
}
}
@@ -244,6 +249,7 @@ void BoxController::loadMoreRows() {
MTP_int(0),
MTP_int(_offsetId ? kFirstPageCount : kPerPageCount),
MTP_int(0),
MTP_int(0),
MTP_int(0)
)).done([this](const MTPmessages_Messages &result) {
_loadRequestId = 0;

View File

@@ -40,17 +40,30 @@ constexpr auto kHangupTimeoutMs = 5000;
using tgvoip::Endpoint;
void ConvertEndpoint(std::vector<tgvoip::Endpoint> &ep, const MTPDphoneConnection &mtc) {
void ConvertEndpoint(
std::vector<tgvoip::Endpoint> &ep,
const MTPDphoneConnection &mtc) {
if (mtc.vpeer_tag.v.length() != 16) {
return;
}
auto ipv4 = tgvoip::IPv4Address(std::string(mtc.vip.v.constData(), mtc.vip.v.size()));
auto ipv6 = tgvoip::IPv6Address(std::string(mtc.vipv6.v.constData(), mtc.vipv6.v.size()));
ep.push_back(Endpoint((int64_t)mtc.vid.v, (uint16_t)mtc.vport.v, ipv4, ipv6, EP_TYPE_UDP_RELAY, (unsigned char*)mtc.vpeer_tag.v.data()));
auto ipv4 = tgvoip::IPv4Address(std::string(
mtc.vip.v.constData(),
mtc.vip.v.size()));
auto ipv6 = tgvoip::IPv6Address(std::string(
mtc.vipv6.v.constData(),
mtc.vipv6.v.size()));
ep.push_back(Endpoint(
(int64_t)mtc.vid.v,
(uint16_t)mtc.vport.v,
ipv4,
ipv6,
EP_TYPE_UDP_RELAY,
(unsigned char*)mtc.vpeer_tag.v.data()));
}
constexpr auto kFingerprintDataSize = 256;
uint64 ComputeFingerprint(const std::array<gsl::byte, kFingerprintDataSize> &authKey) {
uint64 ComputeFingerprint(
const std::array<gsl::byte, kFingerprintDataSize> &authKey) {
auto hash = openssl::Sha1(authKey);
return (gsl::to_integer<uint64>(hash[19]) << 56)
| (gsl::to_integer<uint64>(hash[18]) << 48)
@@ -64,7 +77,10 @@ uint64 ComputeFingerprint(const std::array<gsl::byte, kFingerprintDataSize> &aut
} // namespace
Call::Call(not_null<Delegate*> delegate, not_null<UserData*> user, Type type)
Call::Call(
not_null<Delegate*> delegate,
not_null<UserData*> user,
Type type)
: _delegate(delegate)
, _user(user)
, _type(type) {
@@ -124,7 +140,16 @@ void Call::startOutgoing() {
Expects(_type == Type::Outgoing);
Expects(_state == State::Requesting);
request(MTPphone_RequestCall(_user->inputUser, MTP_int(rand_value<int32>()), MTP_bytes(_gaHash), MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | MTPDphoneCallProtocol::Flag::f_udp_reflector), MTP_int(kMinLayer), MTP_int(kMaxLayer)))).done([this](const MTPphone_PhoneCall &result) {
request(MTPphone_RequestCall(
_user->inputUser,
MTP_int(rand_value<int32>()),
MTP_bytes(_gaHash),
MTP_phoneCallProtocol(
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(kMaxLayer))
)).done([this](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
setState(State::Waiting);
@@ -185,7 +210,15 @@ void Call::answer() {
} else {
_answerAfterDhConfigReceived = false;
}
request(MTPphone_AcceptCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_bytes(_gb), _protocol)).done([this](const MTPphone_PhoneCall &result) {
request(MTPphone_AcceptCall(
MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)),
MTP_bytes(_gb),
MTP_phoneCallProtocol(
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(kMaxLayer))
)).done([this](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
auto &call = result.c_phone_phoneCall();
App::feedUsers(call.vusers);
@@ -248,7 +281,10 @@ QString Call::getDebugLog() const {
void Call::startWaitingTrack() {
_waitingTrack = Media::Audio::Current().createTrack();
auto trackFileName = Auth().data().getSoundPath((_type == Type::Outgoing) ? qsl("call_outgoing") : qsl("call_incoming"));
auto trackFileName = Auth().settings().getSoundPath(
(_type == Type::Outgoing)
? qsl("call_outgoing")
: qsl("call_incoming"));
_waitingTrack->samplePeakEach(kSoundSampleMs);
_waitingTrack->fillFromFile(trackFileName);
_waitingTrack->playInLoop();
@@ -291,7 +327,6 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
}
_id = data.vid.v;
_accessHash = data.vaccess_hash.v;
_protocol = data.vprotocol;
auto gaHashBytes = bytesFromMTP(data.vg_a_hash);
if (gaHashBytes.size() != _gaHash.size()) {
LOG(("Call Error: Wrong g_a_hash size %1, expected %2.").arg(gaHashBytes.size()).arg(_gaHash.size()));
@@ -390,7 +425,16 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
_keyFingerprint = ComputeFingerprint(_authKey);
setState(State::ExchangingKeys);
request(MTPphone_ConfirmCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_bytes(_ga), MTP_long(_keyFingerprint), MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | MTPDphoneCallProtocol::Flag::f_udp_reflector), MTP_int(kMinLayer), MTP_int(kMaxLayer)))).done([this](const MTPphone_PhoneCall &result) {
request(MTPphone_ConfirmCall(
MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)),
MTP_bytes(_ga),
MTP_long(_keyFingerprint),
MTP_phoneCallProtocol(
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(kMaxLayer))
)).done([this](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
auto &call = result.c_phone_phoneCall();
App::feedUsers(call.vusers);
@@ -477,6 +521,18 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
_controller->SetStateCallback([](tgvoip::VoIPController *controller, int state) {
static_cast<Call*>(controller->implData)->handleControllerStateChange(controller, state);
});
if (Global::UseProxy() && Global::UseProxyForCalls()) {
const auto proxy = Global::SelectedProxy();
if (proxy.supportsCalls()) {
Assert(proxy.type == ProxyData::Type::Socks5);
_controller->SetProxy(
tgvoip::PROXY_SOCKS5,
proxy.host.toStdString(),
proxy.port,
proxy.user.toStdString(),
proxy.password.toStdString());
}
}
_controller->Start();
_controller->Connect();
}

View File

@@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Calls {
namespace {
ushort Data[] = {
const ushort Data[] = {
0xd83d, 0xde09, 0xd83d, 0xde0d, 0xd83d, 0xde1b, 0xd83d, 0xde2d, 0xd83d, 0xde31, 0xd83d, 0xde21,
0xd83d, 0xde0e, 0xd83d, 0xde34, 0xd83d, 0xde35, 0xd83d, 0xde08, 0xd83d, 0xde2c, 0xd83d, 0xde07,
0xd83d, 0xde0f, 0xd83d, 0xdc6e, 0xd83d, 0xdc77, 0xd83d, 0xdc82, 0xd83d, 0xdc76, 0xd83d, 0xdc68,
@@ -69,7 +69,7 @@ ushort Data[] = {
0x0030, 0x20e3, 0xd83d, 0xdd1f, 0x2757, 0x2753, 0x2665, 0x2666, 0xd83d, 0xdcaf, 0xd83d, 0xdd17,
0xd83d, 0xdd31, 0xd83d, 0xdd34, 0xd83d, 0xdd35, 0xd83d, 0xdd36, 0xd83d, 0xdd37 };
ushort Offsets[] = {
const ushort Offsets[] = {
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22,
24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46,
48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70,
@@ -119,7 +119,9 @@ std::vector<EmojiPtr> ComputeEmojiFingerprint(not_null<Call*> call) {
for (auto index = 0; index != EmojiCount; ++index) {
auto offset = Offsets[index];
auto size = Offsets[index + 1] - offset;
auto string = QString::fromRawData(reinterpret_cast<QChar*>(Data + offset), size);
auto string = QString::fromRawData(
reinterpret_cast<const QChar*>(Data + offset),
size);
auto emoji = Ui::Emoji::Find(string);
Assert(emoji != nullptr);
}
@@ -131,7 +133,9 @@ std::vector<EmojiPtr> ComputeEmojiFingerprint(not_null<Call*> call) {
auto index = value % EmojiCount;
auto offset = Offsets[index];
auto size = Offsets[index + 1] - offset;
auto string = QString::fromRawData(reinterpret_cast<QChar*>(Data + offset), size);
auto string = QString::fromRawData(
reinterpret_cast<const QChar*>(Data + offset),
size);
auto emoji = Ui::Emoji::Find(string);
Assert(emoji != nullptr);
result.push_back(emoji);

View File

@@ -60,7 +60,8 @@ void Instance::playSound(Sound sound) {
case Sound::Busy: {
if (!_callBusyTrack) {
_callBusyTrack = Media::Audio::Current().createTrack();
_callBusyTrack->fillFromFile(Auth().data().getSoundPath(qsl("call_busy")));
_callBusyTrack->fillFromFile(
Auth().settings().getSoundPath(qsl("call_busy")));
}
_callBusyTrack->playOnce();
} break;
@@ -68,7 +69,8 @@ void Instance::playSound(Sound sound) {
case Sound::Ended: {
if (!_callEndedTrack) {
_callEndedTrack = Media::Audio::Current().createTrack();
_callEndedTrack->fillFromFile(Auth().data().getSoundPath(qsl("call_end")));
_callEndedTrack->fillFromFile(
Auth().settings().getSoundPath(qsl("call_end")));
}
_callEndedTrack->playOnce();
} break;
@@ -76,7 +78,8 @@ void Instance::playSound(Sound sound) {
case Sound::Connecting: {
if (!_callConnectingTrack) {
_callConnectingTrack = Media::Audio::Current().createTrack();
_callConnectingTrack->fillFromFile(Auth().data().getSoundPath(qsl("call_connect")));
_callConnectingTrack->fillFromFile(
Auth().settings().getSoundPath(qsl("call_connect")));
}
_callConnectingTrack->playOnce();
} break;

View File

@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/calls_panel.h"
#include "data/data_photo.h"
#include "data/data_session.h"
#include "calls/calls_emoji_fingerprint.h"
#include "styles/style_calls.h"
#include "styles/style_history.h"
@@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "observer_peer.h"
#include "platform/platform_specific.h"
#include "window/main_window.h"
#include "layout.h"
namespace Calls {
namespace {
@@ -429,7 +431,7 @@ void Panel::processUserPhoto() {
_user->loadUserpic(true);
}
const auto photo = _user->userpicPhotoId()
? App::photo(_user->userpicPhotoId())
? Auth().data().photo(_user->userpicPhotoId()).get()
: nullptr;
if (isGoodUserPhoto(photo)) {
photo->full->load(true);
@@ -441,7 +443,7 @@ void Panel::processUserPhoto() {
void Panel::refreshUserPhoto() {
const auto photo = _user->userpicPhotoId()
? App::photo(_user->userpicPhotoId())
? Auth().data().photo(_user->userpicPhotoId()).get()
: nullptr;
const auto isNewPhoto = [&](not_null<PhotoData*> photo) {
return photo->full->loaded()

View File

@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "observer_peer.h"
#include "boxes/abstract_box.h"
#include "base/timer.h"
#include "layout.h"
namespace Calls {
namespace {

View File

@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "chat_helpers/bot_keyboard.h"
#include "history/history.h"
#include "history/history_item_components.h"
#include "styles/style_widgets.h"
#include "styles/style_history.h"
@@ -279,7 +280,7 @@ void BotKeyboard::updateSelected() {
auto p = mapFromGlobal(_lastMousePos);
auto x = rtl() ? st::botKbScroll.width : _st->margin;
auto link = _impl->getState(p - QPoint(x, _st->margin));
auto link = _impl->getLink(p - QPoint(x, _st->margin));
if (ClickHandler::setActive(link, this)) {
Ui::Tooltip::Hide();
setCursor(link ? style::cur_pointer : style::cur_default);

View File

@@ -9,14 +9,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/tooltip.h"
namespace style {
struct BotKeyboardButton;
} // namespace style
class ReplyKeyboard;
class BotKeyboard
: public TWidget
, public Ui::AbstractTooltipShower
, public ClickHandlerHost {
Q_OBJECT
public:
BotKeyboard(QWidget *parent);

View File

@@ -21,17 +21,17 @@ stickersRestrictedLabel: FlatLabel(defaultFlatLabel) {
textFg: noContactsColor;
}
stickersTrendingHeader: 45px;
stickersTrendingSkip: 15px;
stickersTrendingHeader: 56px;
stickersTrendingSkip: 4px;
stickersTrendingHeaderFont: semiboldFont;
stickersTrendingHeaderFg: windowFg;
stickersTrendingHeaderTop: 0px;
stickersTrendingHeaderTop: 11px;
stickersTrendingSubheaderFont: normalFont;
stickersTrendingSubheaderFg: windowSubTextFg;
stickersTrendingSubheaderTop: 20px;
stickersTrendingSubheaderTop: 31px;
stickersTrendingAddTop: 3px;
stickersTrendingAddTop: 14px;
stickersTrendingAdd: RoundButton(defaultActiveButton) {
width: -16px;
height: 26px;
@@ -90,7 +90,7 @@ stickersRowDuration: 200;
stickersSettings: icon {{ "emoji_settings", emojiIconFg }};
stickersTrending: icon {{ "emoji_trending", emojiIconFg }};
stickersFaved: icon {{ "emoji_faved", emojiIconFg }};
stickersSearch: icon {{ "stickers_search", emojiIconFg, point(0px, 1px) }};
stickersSettingsUnreadSize: 17px;
stickersSettingsUnreadPosition: point(4px, 5px);
@@ -209,6 +209,8 @@ stickerGroupCategoryAdd: stickersTrendingAdd;
stickersToastMaxWidth: 340px;
stickersToastPadding: margins(16px, 13px, 16px, 12px);
stickersEmpty: icon {{ "stickers_empty", windowSubTextFg }};
inlineBotsScroll: ScrollArea(defaultSolidScroll) {
deltat: stickerPanPadding;
deltab: stickerPanPadding;

View File

@@ -14,11 +14,15 @@ namespace Ui {
namespace Emoji {
inline utf16string QStringToUTF16(const QString &string) {
return utf16string(reinterpret_cast<const utf16char*>(string.constData()), string.size());
return utf16string(
reinterpret_cast<const utf16char*>(string.constData()),
string.size());
}
inline QString QStringFromUTF16(utf16string string) {
return QString::fromRawData(reinterpret_cast<const QChar*>(string.data()), string.size());
return QString::fromRawData(
reinterpret_cast<const QChar*>(string.data()),
string.size());
}
constexpr auto kSuggestionMaxLength = internal::kReplacementMaxLength;

View File

@@ -346,12 +346,15 @@ void SuggestionsWidget::leaveEventHook(QEvent *e) {
return TWidget::leaveEventHook(e);
}
SuggestionsController::SuggestionsController(QWidget *parent, not_null<QTextEdit*> field) : QObject(nullptr)
SuggestionsController::SuggestionsController(QWidget *parent, not_null<QTextEdit*> field)
: QObject(nullptr)
, _field(field)
, _container(parent, st::emojiSuggestionsDropdown)
, _suggestions(_container->setOwnedWidget(object_ptr<Ui::Emoji::SuggestionsWidget>(parent, st::emojiSuggestionsMenu))) {
_container->setAutoHiding(false);
setReplaceCallback(nullptr);
_field->installEventFilter(this);
connect(_field, &QTextEdit::textChanged, this, [this] { handleTextChange(); });
connect(_field, &QTextEdit::cursorPositionChanged, this, [this] { handleCursorPositionChange(); });
@@ -363,6 +366,23 @@ SuggestionsController::SuggestionsController(QWidget *parent, not_null<QTextEdit
handleTextChange();
}
void SuggestionsController::setReplaceCallback(
base::lambda<void(
int from,
int till,
const QString &replacement)> callback) {
if (callback) {
_replaceCallback = std::move(callback);
} else {
_replaceCallback = [=](int from, int till, const QString &replacement) {
auto cursor = _field->textCursor();
cursor.setPosition(from);
cursor.setPosition(till, QTextCursor::KeepAnchor);
cursor.insertText(replacement);
};
}
}
void SuggestionsController::handleTextChange() {
_ignoreCursorPositionChange = true;
InvokeQueued(this, [this] { _ignoreCursorPositionChange = false; });
@@ -374,7 +394,7 @@ void SuggestionsController::handleTextChange() {
}
QString SuggestionsController::getEmojiQuery() {
if (!cReplaceEmojis()) {
if (!Global::SuggestEmoji()) {
return QString();
}
@@ -411,10 +431,23 @@ QString SuggestionsController::getEmojiQuery() {
return QString();
}
auto isSuggestionChar = [](QChar ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || (ch == '_') || (ch == '-') || (ch == '+');
const auto isUpperCaseLetter = [](QChar ch) {
return (ch >= 'A' && ch <= 'Z');
};
auto isGoodCharBeforeSuggestion = [isSuggestionChar](QChar ch) {
const auto isLetter = [](QChar ch) {
return (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9');
};
const auto isSuggestionChar = [](QChar ch) {
return (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9')
|| (ch == '_')
|| (ch == '-')
|| (ch == '+');
};
const auto isGoodCharBeforeSuggestion = [&](QChar ch) {
return !isSuggestionChar(ch) || (ch == 0);
};
Assert(position > 0 && position <= text.size());
@@ -427,7 +460,22 @@ QString SuggestionsController::getEmojiQuery() {
if (position > i + 1) {
// Skip colon and the first letter.
_queryStartPosition += i + 2;
return text.mid(i, position - i);
const auto length = position - i;
auto result = text.mid(i, length);
const auto upperCaseLetters = std::count_if(
result.begin(),
result.end(),
isUpperCaseLetter);
const auto letters = std::count_if(
result.begin(),
result.end(),
isLetter);
if (letters == upperCaseLetters && letters == 1) {
// No upper case single letter suggestions.
// We don't want to suggest emoji on :D and :-P
return QString();
}
return result.toLower();
}
}
return QString();
@@ -443,24 +491,14 @@ QString SuggestionsController::getEmojiQuery() {
}
void SuggestionsController::replaceCurrent(const QString &replacement) {
auto cursor = _field->textCursor();
auto suggestion = getEmojiQuery();
if (suggestion.isEmpty()) {
_suggestions->showWithQuery(QString());
} else {
cursor.setPosition(cursor.position() - suggestion.size(), QTextCursor::KeepAnchor);
cursor.insertText(replacement);
}
auto emojiText = GetSuggestionEmoji(QStringToUTF16(replacement));
if (auto emoji = Find(QStringFromUTF16(emojiText))) {
if (emoji->hasVariants()) {
auto it = cEmojiVariants().constFind(emoji->nonColoredId());
if (it != cEmojiVariants().cend()) {
emoji = emoji->variant(it.value());
}
}
AddRecent(emoji);
const auto cursor = _field->textCursor();
const auto position = cursor.position();
const auto from = position - suggestion.size();
_replaceCallback(from, position, replacement);
}
}

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