Compare commits

...

342 Commits

Author SHA1 Message Date
John Preston
534058fe9b Alpha version 1.1.29. 2017-12-09 22:21:38 +04:00
John Preston
6d62673e9e Fix crash in HistoryWidget. 2017-12-09 22:21:38 +04:00
John Preston
677dbd5d6e Alpha version 1.1.28: Fix build for Xcode. 2017-12-09 20:01:40 +04:00
John Preston
452440f50b Alpha version 1.1.28.
- Bug fixes and other minor improvements.
2017-12-09 19:17:23 +04:00
John Preston
5a7d8bcffb Add audio playlist using Info::Media::ListWidget. 2017-12-09 19:13:06 +04:00
John Preston
63e89ddc9a Fix replies by stickers and inline bot results. 2017-12-09 16:39:41 +04:00
John Preston
4e2c8bbc26 Use SharedMediaMergedViewer() for audio player.
That way audio files and voice/video messages will play in context
(one after another with ability to go to next or previous in player)
almost always, no matter at what part of message history we are.
2017-12-09 14:02:51 +04:00
John Preston
9bbcbd4bb3 Remove all legacy media overview code. 2017-12-08 22:34:26 +04:00
John Preston
273ac5eaf1 Add some more public keys. 2017-12-08 20:26:27 +04:00
John Preston
951db83ab6 Index bad audio files to Shared Files Overview.
Fixes #4120.
2017-12-08 19:53:04 +04:00
chaplin89
a868c7bc8b Avoid generating multiple time the forward declarations in the headers generated by codegen_style. 2017-12-08 19:49:24 +04:00
John Preston
a403ad7d37 Always pass all users to add group member box. 2017-12-08 18:25:29 +04:00
John Preston
90f5f7dded Fix possible crash in timer timeout values. 2017-12-08 18:15:00 +04:00
John Preston
aef88559e8 Fix possible crash in HistoryWidget.
Stack in crash reports leads to something like that:
- HistoryWidget::showHistory
- _scroll->setOwnedWidget
- Ui::ScrollArea::onScrolled
- sendSynteticMouseEvent
- Info::Media::ListWidget::enterEventHook
- Info::Media::ListWidget::mouseAction?Update
- Overview::Layout::ItemBase::clickHandlerActiveChanged
- AuthSessionData::requestItemRepaint
- HistoryWidget::repaintHistoryItem

Workaround:
- Don't accept repaint item requests while _list is not set yet.
2017-12-08 17:54:55 +04:00
John Preston
6295d85ef2 Fix possible assertion violation in PeerListBox.
Very long stack in crash reports leads to something like that:
- PeerListBox::prepare
- PeerListBox::createMultiSelect
- PeerListBox::updateScrollSkips
- BoxContent::setInnerTopSkip
- _scroll->scrollToY
- sendSynteticMouseEvent
- ChatHelpers::TabbedPanel::showAnimated
- QWidget::render
- QWidgetPrivate::sendPendingMoveAndResizeEvents
- PeerListBox::resizeEvent
- _select->resizeToWidth(0)
- MultiSelect::Inner::computeItemsGeometry(0)

Workaround:
- Don't scrollToY if PeerListBox width was not yet set.
- Initial _scrollBottomFixed is false (at first createMultiSelect).
2017-12-08 17:36:17 +04:00
John Preston
a27ea2d631 Fix possible crash in mtpFileLoader.
If several cdn file parts hashes are received in getCdnFileHashesDone
and some middle one of them cancels the entire loader (for example
because of a file write error) a !_finished assert violation happens.
2017-12-08 17:13:13 +04:00
John Preston
de8de84a33 Fix possible crash in CalendarBox.
If month change notification was posted async there was a possibility
to get a mousePressEvent() with already new Context field values, but
with old _selected value. Those two could be inconsistent leading to
an assert violation in (_selected + _context->daysShift() >= 0).
2017-12-08 16:44:52 +04:00
John Preston
80bb6b65a7 Fix possible crash. 2017-12-08 15:53:28 +04:00
John Preston
f8963d7e4b Read silent flag from PeerData, not SilentToggle. 2017-12-08 15:52:12 +04:00
John Preston
c79d16a0d6 Auto-choose first search row in PeerListBox. 2017-12-08 13:30:30 +04:00
John Preston
aa16bcd604 Add a special key for saved messages userpic bg. 2017-12-08 13:23:55 +04:00
John Preston
935232eaa2 Don't use AEC on modern macOS. 2017-12-08 13:13:05 +04:00
John Preston
e273695cc9 Fix planar audio playback (for example .flac).
Also add some more crash information logging.

Fixes #4120.
2017-12-08 12:57:43 +04:00
John Preston
827784e3b2 Focus search field in Info layer. 2017-12-08 12:22:02 +04:00
John Preston
b501af0b8f Add search button to info members header. 2017-12-08 12:14:30 +04:00
John Preston
8f87cfe29d Fix explicit working dir by "-workdir" in Windows.
Regression was introduced in ff84962148.

Fixes #4129.
2017-12-08 12:13:42 +04:00
John Preston
79398fe6cf Add call button to Info::Profile top bar. 2017-12-07 19:17:53 +04:00
John Preston
355747d7bf Remove send actions in Saved Messages.
Fixes #4122.
2017-12-07 18:27:59 +04:00
John Preston
a032f24d58 Fix explicit working dir by "-workdir" argument.
Regression was introduced in ff84962148.

Fixes #4123.
2017-12-07 17:56:36 +04:00
John Preston
320105f201 Allow searching for '@' in the chats filter field.
Fixes #4121.
2017-12-07 17:43:06 +04:00
John Preston
54984efa0a Fix small files layout in Saved Messages.
Minimal message and media width are less because of the goto-button.
2017-12-07 17:43:05 +04:00
John Preston
d57f5460b7 Use ShowForwardMessageBox in Info::Media. 2017-12-07 17:43:05 +04:00
John Preston
5bc47e5203 Move shareContact and readServerHistory to ApiWrap.
Also allow non-confirming contact info sharing to Saved Messages.
2017-12-07 17:43:05 +04:00
John Preston
f0a03223e8 Share contact instantly to Saved Messages. 2017-12-07 12:56:10 +04:00
John Preston
007ab3b7b8 Fix crash in RSA public key wrapper. 2017-12-07 09:34:11 +04:00
Nicholas Guriev
f813bb704f Optimize key initialization
* Do not do redundant copying of numbers.
2017-12-07 09:15:10 +04:00
Nicholas Guriev
93809ec404 Fix build against OpenSSL 1.1
Closes: #3196
2017-12-07 09:15:10 +04:00
Mike Zueff
64e9958585 Fixed awesome WM tray icon. 2017-12-07 09:11:39 +04:00
John Preston
067138f1bf Alpha version 1.1.27: Update lang phrases. 2017-12-06 20:00:31 +04:00
John Preston
cfa88b840a Alpha 1.1.27: Fix build error. 2017-12-06 20:00:31 +04:00
John Preston
32f955404b Alpha version 1.1.27.
- Bookmark messages by forwarding them to "Saved Messages".
Access them from the Chats list or from the side menu.
2017-12-06 19:30:51 +04:00
John Preston
ff84962148 Stop using current working directory on Windows.
Links generated by system sometimes have weird working directories,
like C:\Windows\system32. Stop trying to use current working folder
as a place for program data. Instead always try to use current exe
folder and if we were unable use app data folder.
2017-12-06 19:07:19 +04:00
John Preston
727f8aec13 Fix admin/creator status in megagroup members list. 2017-12-06 18:55:10 +04:00
John Preston
d77afef8b0 Hide Share contact button in saved messages. 2017-12-06 18:41:37 +04:00
John Preston
775cede16f Use separate phrases for clearing saved messages. 2017-12-06 18:39:27 +04:00
John Preston
c6d3fd883a Display right action button not too high. 2017-12-06 18:15:41 +04:00
John Preston
1473c14668 Forward messages to Saved Messages instantly. 2017-12-06 17:56:40 +04:00
John Preston
6764a3cc86 Replace SelectedItemSet with MessageIdsList.
Use vector<FullMsgId> everywhere instead QMap<..,HistoryItem*>.
The old way the app crashed in case some messages were deleted.
If the items are needed use HistoryItemsList=vector<HistoryItem*>.
2017-12-06 14:13:38 +04:00
John Preston
3845985a6b Fix third column appearing on window resize. 2017-12-06 11:05:34 +04:00
John Preston
76a716007c Closed beta 1.1.26.2. 2017-12-05 20:49:45 +04:00
John Preston
993877b0d4 Change main menu cloud icon to saved messages. 2017-12-05 20:48:03 +04:00
John Preston
8b3d203861 Display saved messages senders correctly. 2017-12-05 20:38:13 +04:00
John Preston
85d8273009 Implement correct saved messages history layout.
Forwarded info is displayed as a message author info (name/photo).
Outgoing messages without forwarded info are displayed as out().
Messages with save_from_ info have a button for GoToOriginal().
2017-12-05 20:14:28 +04:00
John Preston
f8e094392f Fix ripple animation glitch in history top bar. 2017-12-05 20:14:15 +04:00
John Preston
46bafc2dcc Support Saved messages in chats list and forwards. 2017-12-05 18:07:01 +04:00
John Preston
e4ce08e64e Show other shared media links in Saved Photos. 2017-12-05 16:23:08 +04:00
John Preston
aebdc2fd94 Add custom userpic rendering for Saved Messages. 2017-12-05 15:50:32 +04:00
John Preston
1d85c8a6b6 API scheme updated to layer 73. 2017-12-05 12:44:27 +04:00
John Preston
5eeb8143b6 Move EmptyUserpic from data_peer to empty_userpic. 2017-12-05 12:44:27 +04:00
John Preston
68009b6fba Refactor userpic storage and access in PeerData. 2017-12-05 11:58:18 +04:00
John Preston
62568daffe Refactor NotifySettings in PeerData. 2017-12-04 21:48:45 +04:00
John Preston
116e3fd9c5 Fix admin stars disappearing in members list. 2017-12-04 16:08:43 +04:00
John Preston
76f951e3e6 Show members list in the third column. 2017-12-04 15:45:15 +04:00
John Preston
1a273702d3 Revert closed beta version. 2017-12-04 13:52:22 +04:00
John Preston
4678de0440 Closed beta 1.1.26.1. 2017-12-04 13:51:44 +04:00
John Preston
e1c68892d4 Show third column only when explicitly requested.
This allows you to show info in layer from mention links.
2017-12-04 13:42:05 +04:00
John Preston
629c216a7f Fix storage size variables, use qint64.
Fixes #4110.
2017-12-03 20:51:31 +04:00
John Preston
f3c8da4819 Request all admins when first opening a supergroup. 2017-12-03 20:43:42 +04:00
John Preston
9ba482f56f Fix crash in edit group info box. 2017-12-03 19:24:33 +04:00
John Preston
2a59802a16 Alpha version 1.1.26: Fix release script. 2017-12-02 18:57:13 +04:00
John Preston
8668d43032 Alpha version 1.1.26.
- Admin badges in supergroup messages.
- Fix crashing on launch in OS X 10.6.
- Bug fixes and other minor improvements.
2017-12-02 18:55:47 +04:00
John Preston
d6f7cae024 Fix two crashes in OS X 10.6.
Disable rtl control chars (harfbuzz-ng crashes on them).
Disable creating state of not yet created top level windows.
2017-12-02 16:10:52 +04:00
John Preston
8391d43057 Use EditPeerInfoBox for editing groups.
This allows to edit group invite links.
Rename EditNameTitleBox to EditNameBox, used only from Settings.
2017-12-02 16:04:22 +04:00
John Preston
da77c10f60 Hide three-dot peer menu when peer changes. 2017-12-02 15:11:01 +04:00
John Preston
301aa9572f Apply channel admin edition changes. 2017-12-02 15:07:27 +04:00
John Preston
675499df4d Fix render bug in single column layout. 2017-12-02 14:22:48 +04:00
John Preston
0a1165dac9 Remove locking in crash annotations.
We removed ffmpeg crash annotations so now all are from main thread.
2017-12-02 13:28:15 +04:00
John Preston
a495de7cf8 Ask OpenAL to use kDefaultFrequency (48 kHz). 2017-12-02 13:27:32 +04:00
John Preston
2161858088 Fail resampling audio with inconsistent frames. 2017-12-02 12:58:52 +04:00
John Preston
001be82566 Add some more checks to file downloader. 2017-12-02 12:32:43 +04:00
John Preston
85b3d3f64d Display admin badges in supergroups.
Also prefer std containers to Qt and OrderedSet in data_peer.
2017-12-01 22:38:44 +04:00
John Preston
3bdce06e19 Use peer colors uniformly with mobile apps. 2017-12-01 14:21:40 +04:00
John Preston
36fe4ff327 Alpha version 1.1.25.
- Bug fixes and other minor improvements.
2017-11-30 22:34:57 +04:00
John Preston
afd1548533 Attempt to fix a crash in touch event handlers. 2017-11-30 22:18:39 +04:00
John Preston
595af2c6d9 Rename weak(QObject*) to make_weak(QObject*). 2017-11-30 22:04:13 +04:00
John Preston
2bbf17b672 Fix t.me/share links.
Regression was introduced in ffc20e4492.

Fixes #4099.
2017-11-30 21:47:58 +04:00
John Preston
43570d1613 Check current chat before auto-closing it.
Close current chat only if it is the one being delete-and-exit'ed.
2017-11-30 21:35:35 +04:00
John Preston
2432845df2 Optimize and rename base::weak_unique_ptr.
Rename base::enable_weak_from_this -> base::has_weak_ptr.
Rename base::weak_unique_ptr -> base::weak_ptr.
Rename base::make_weak_unique -> base::make_weak.
Rename base/weak_unique_ptr.h -> base/weak_ptr.h
2017-11-30 21:33:27 +04:00
John Preston
0bf854bf18 Fix edit name button in Settings.
Regression was introduced in 703b944839.
2017-11-30 18:01:01 +04:00
John Preston
a0c8d522ef Save window extension on layer->section migration.
If the third section is shown inside the existing window remember
it as a zero window extension or third section show. That way it
will hide correctly when it is closed by X button.

Partially fixes #4091.
2017-11-30 17:08:51 +04:00
John Preston
c10588a7dc Merge group-supergroup history in jump-to-date.
Fixes #4094.
2017-11-30 16:50:13 +04:00
John Preston
13ab055fe0 Add debug information about crash in ffmpeg. 2017-11-30 15:41:15 +04:00
John Preston
2e972fb678 Hide "Delete for {user}" in chats with bots.
Fixes #3818.
2017-11-30 15:06:30 +04:00
John Preston
5b7059dccd Fix crash in shared media save state. 2017-11-30 12:15:21 +04:00
John Preston
ad6ddcb507 Fix crash in selecting unsent messages.
Also add some more checks in file downloads and serialization.
2017-11-30 11:14:31 +04:00
John Preston
6994201d50 Fix travis and appveyor builds. 2017-11-29 22:33:16 +04:00
John Preston
cc1df6a068 Alpha version 1.1.24.
- Radically improved navigation. New side panel on the right
with quick access to shared media and group members.
- Pinned Messages. If you are a channel admin, pin messages
to focus your subscribers' attention on important announcements.
- Also supported clearing history in supergroups and added
a host of minor improvements.
2017-11-29 19:10:03 +04:00
John Preston
88b1552229 Closed beta 1.1.23.12. 2017-11-29 00:01:18 +04:00
John Preston
41b143cb7e Fix and improve back navigation with three columns. 2017-11-29 00:01:04 +04:00
John Preston
196ff7f4c1 Don't apply count from getParticipants(Recent). 2017-11-28 22:30:01 +04:00
John Preston
ff16897dde Improve supergroup members list reusability. 2017-11-28 20:20:05 +04:00
John Preston
300e55e610 Fix delete button in shared media selections. 2017-11-28 19:16:28 +04:00
John Preston
f716041073 Closed beta 1.1.23.11. 2017-11-28 14:05:23 +04:00
John Preston
a63abe5154 Add some more crash debug information. 2017-11-28 14:05:11 +04:00
John Preston
c04991f707 Redesign round checkbox animations. 2017-11-28 00:54:31 +04:00
John Preston
ddd57517df Fix text overflow in history top bar. 2017-11-27 19:09:26 +04:00
John Preston
d014b47958 Move Info::TopBarOverride to Info::TopBar.
This allows to improve animations in shared media items selection.
2017-11-27 15:43:57 +04:00
John Preston
6afe18503d wip redesign info top bar 2017-11-26 21:05:52 +04:00
John Preston
837dac50fa Fix build for the original range-v3. 2017-11-26 18:20:22 +04:00
John Preston
6a4aa184f3 Closed beta 1.1.23.10. 2017-11-24 21:42:19 +04:00
John Preston
20c9280ada Add some more debug info for crashes. 2017-11-24 21:41:31 +04:00
John Preston
fea122ae12 Handle PHONE_NUMBER_BANNED error in login. 2017-11-24 21:41:09 +04:00
John Preston
86c0205faa Handle USERS_TOO_FEW error in group creation. 2017-11-24 20:33:06 +04:00
John Preston
9f76be9d26 Elide 'Delete for {user}' checkbox text. 2017-11-24 20:28:14 +04:00
John Preston
7705696d54 Hide all PopupMenu when enabling local passcode. 2017-11-24 20:06:35 +04:00
John Preston
bb7ab625c1 Fix channel admin rights checking. 2017-11-24 20:05:50 +04:00
John Preston
da386f2c2e Update user status in Info::Profile cover. 2017-11-24 19:51:47 +04:00
John Preston
0ced28f991 Nice animations when selecting shared media items. 2017-11-24 19:47:09 +04:00
John Preston
9dc39cb758 Add slide animation to Info::TopBarOverride. 2017-11-24 18:12:39 +04:00
John Preston
9eacb11f3c Fix render lag in widgets resizeEvent()->show().
ScrollArea calls show() in ScrollBar::resizeEvent. If this event
handlers was called from SendPending...() you could set fake .._Shown
attribute on, call resizeEvent() and remove this attribute even if it
should not be removed already - after call to show().
2017-11-24 17:07:36 +04:00
John Preston
4b1d15f968 Closed beta 1.1.23.9. 2017-11-23 19:46:08 +04:00
John Preston
7395cc21b8 Update libtgvoip, opus to 1.2.1 and ffmpeg to 3.4. 2017-11-23 19:41:59 +04:00
John Preston
efdba3a482 Handle errors in getMessages(). 2017-11-23 19:41:13 +04:00
John Preston
39428841e4 Improve selected shared media items layout.
Also fix night mode theme bug in report spam panel.
2017-11-23 18:58:00 +04:00
John Preston
981063596a Add nice scroll to the bottom of the Info layer. 2017-11-23 17:10:50 +04:00
John Preston
67d4eb688a Reverse user and chat profile photos. 2017-11-23 13:58:12 +04:00
John Preston
da71938d18 Link libstdc++ statically in Updater.
This will allow running it on Ubuntu 12.04 when it was built on 14.04.
2017-11-23 09:29:58 +04:00
John Preston
2850d456d0 Closed beta 1.1.23.8: Test an upstream fix backport for macOS issue. 2017-11-22 21:53:10 +04:00
John Preston
5063a22155 Closed beta 1.1.23.8. 2017-11-22 18:03:00 +04:00
John Preston
98896ab5ac Fix crash in RpWidget::event() from alive().done() 2017-11-22 18:02:29 +04:00
John Preston
5913e6d187 Closed beta 1.1.23.7. 2017-11-22 15:11:41 +04:00
John Preston
f477aea2a5 Add some more debug info for crashes. 2017-11-22 15:10:11 +04:00
John Preston
5803edb77b Add members from info to mgInfo->lastParticipants. 2017-11-22 13:56:00 +04:00
John Preston
f6ba59ed14 Improve group stickers choose process.
Allow to choose from featured if used has no his own sets.
Allow to choose group sticker set from group info box.
2017-11-22 13:31:02 +04:00
John Preston
542ba89f25 Edit pre-history visibility in megagroups. 2017-11-22 12:04:45 +04:00
John Preston
2387b66e86 Allow supergroup members to clear history. 2017-11-22 12:04:24 +04:00
John Preston
75d8d01b17 Allow pinned messages in channels. 2017-11-21 18:27:48 +04:00
John Preston
b337d54623 Use custom base::overload() helper. 2017-11-21 18:27:48 +04:00
John Preston
44e94bfbf5 Add workaround for macOS leaveEvent() bugs.
On macOS sometimes when mouse leaves the window we don't receive leaveEvent()
calls in the nested widgets, like buttons, only for the window itself.
2017-11-21 18:27:48 +04:00
John Preston
d93c1ccbaa Improve compile time. 2017-11-21 14:20:52 +04:00
John Preston
6ca105a290 Minimal layer 72 support. 2017-11-20 23:54:05 +04:00
John Preston
bccd801874 API scheme updated to layer 72. 2017-11-20 16:33:12 +04:00
John Preston
eb8800f2d4 Replace $ with _ in rpl::mappers. 2017-11-20 16:32:55 +04:00
John Preston
ac99318f34 Use ranges:: algorithms instead of base:: 2017-11-20 16:24:00 +04:00
John Preston
bc7c88c511 Fix build in Xcode / GCC. 2017-11-19 20:31:58 +04:00
John Preston
f1f955b7ac Pass already-members when adding members to channel. 2017-11-19 18:41:52 +04:00
John Preston
68bc8d0231 Add range-v3 library. 2017-11-19 18:37:07 +04:00
John Preston
04a1cff24a Fix wrong unread counter in history top bar. 2017-11-19 15:52:15 +04:00
John Preston
de15da8a93 Improve info layer presentation. 2017-11-19 15:37:15 +04:00
John Preston
59938791ef Closed beta 1.1.23.6: Log crash info. 2017-11-18 00:04:22 +04:00
John Preston
3ef0bcc5d5 Closed beta 1.1.23.6. 2017-11-17 22:52:16 +04:00
John Preston
15d2ce150d Remove Send Message animation in !Wrap::Side 2017-11-17 21:02:49 +04:00
John Preston
33ae4b176a No shared media empty placeholders while loading. 2017-11-17 20:20:31 +04:00
John Preston
4aae4f9399 Show channel members inside Info as well. 2017-11-17 20:06:20 +04:00
John Preston
fc4c31b673 Make members header a button. 2017-11-17 19:34:51 +04:00
John Preston
88d7f172ca Improve unread counter for HistoryTopBarWidget. 2017-11-17 18:54:01 +04:00
John Preston
bef87c6dff Allow showing chat members in a special section. 2017-11-17 17:23:36 +04:00
John Preston
747ebd2136 Make links clickable in channel descriptions. 2017-11-17 11:42:53 +04:00
John Preston
41873412e7 Fix crash and improve info navigation. 2017-11-17 11:33:20 +04:00
John Preston
0811190527 Closed beta 1.1.23.5: Fix build for Xcode and GCC. 2017-11-17 11:09:43 +04:00
John Preston
0a5ba3490d Closed beta 1.1.23.5. 2017-11-16 21:20:27 +04:00
John Preston
55616a4d1b Inject active peer profile on the stack bottom.
Always have active peer profile on the bottom of third column stack.
2017-11-16 21:19:41 +04:00
John Preston
c872cd76e1 Improve window extension by third column. 2017-11-16 20:43:52 +04:00
John Preston
cf977cb41a Improve history -> profile top bar navigation. 2017-11-16 19:24:01 +04:00
John Preston
903aa46e5c Disable tabs in third column info. 2017-11-16 13:13:17 +04:00
John Preston
131efa11be Various fixes. 2017-11-16 11:45:55 +04:00
John Preston
5a159d0204 Improve string encoding. 2017-11-16 07:59:12 +04:00
John Preston
7fdeab829f Paint native title instead of using custom. 2017-11-16 07:59:12 +04:00
John Preston
4e1b94d37d Allow 3 photo/video in the minimal third column. 2017-11-16 07:59:12 +04:00
John Preston
388d743d29 Add confirmation on leaving group/channel. 2017-11-16 07:59:12 +04:00
John Preston
8dfccf55d1 Add shared media empty placeholders. 2017-11-16 07:59:12 +04:00
John Preston
fafcd02e7c Improve Emoji / GIFs list variable width support. 2017-11-16 07:59:12 +04:00
John Preston
defa0ae4d0 Improve stickers list variable width support. 2017-11-16 07:59:12 +04:00
John Preston
7db80d20f1 Closed beta 1.1.23.4. 2017-11-16 07:59:12 +04:00
John Preston
a86788f4d7 Improve info section navigation.
Also fix render glitch in StickersListWidget.
2017-11-16 07:59:12 +04:00
John Preston
aecc119bac Add fast chat photo upload to info profile. 2017-11-16 07:59:11 +04:00
John Preston
8dd3f24285 Replace Profile::UserpicButton with one from Ui:: 2017-11-16 07:59:11 +04:00
John Preston
830c6a4894 Replace PeerAvatarButton with UserpicButton. 2017-11-16 07:59:11 +04:00
John Preston
3d37ac9235 Replace NewAvatarButton with UserpicButton.
This new control should also replace PeerAvatarButton and
Profile::UserpicButton and deliver all the best of those three.
2017-11-16 07:59:11 +04:00
John Preston
3deea14559 Remove old shared media overview section.
Also move window/top_bar_widget to history/history_top_bar_widget.
2017-11-16 07:59:11 +04:00
John Preston
534b578598 Fix crash when switching two columns at once. 2017-11-16 07:59:11 +04:00
John Preston
8355722f4e Closed beta 1.1.23.3. 2017-11-16 07:59:11 +04:00
John Preston
866ff628b7 Fix render bug, enable wide third column. 2017-11-16 07:59:11 +04:00
John Preston
fe9630bb20 Allow to resize third column. 2017-11-16 07:59:11 +04:00
John Preston
bca9b3ca3f Extract a reusable Ui::ResizeArea class. 2017-11-16 07:59:11 +04:00
John Preston
3a25313e61 Fix restoring shared media state. 2017-11-16 07:59:11 +04:00
John Preston
fc66550a32 Support variable width tabs slider. 2017-11-16 07:59:11 +04:00
John Preston
0255d0c59e Support any size in the tabbed selector. 2017-11-16 07:59:10 +04:00
John Preston
5c12b0e5fa Use /permissive- flag for Visual Studio builds. 2017-11-16 07:59:10 +04:00
John Preston
aa160e775c Fix huge CPU consumption in the group info profile. 2017-11-16 07:59:10 +04:00
John Preston
d3c152022c Closed beta 1.1.23.2 2017-11-16 07:59:10 +04:00
John Preston
dbb011fc56 Add members link in info for channel admins. 2017-11-16 07:59:10 +04:00
John Preston
a6df928d45 Improve copy of info profile phrases. 2017-11-16 07:59:10 +04:00
John Preston
dd3ae22e08 Save data from EditPeerInfoBox. 2017-11-16 07:59:10 +04:00
John Preston
8ff0120642 Add EditPeerInfoBox without saving. 2017-11-16 07:59:10 +04:00
John Preston
3998fad7ef Add manage supergroup / channel box. 2017-11-16 07:59:10 +04:00
John Preston
7f8cdf85d5 Grow history stack following joinchat links. 2017-11-16 07:59:10 +04:00
John Preston
1871425b2d Add 'X' and admin star in group info members. 2017-11-16 07:59:10 +04:00
John Preston
5f0ba48309 Add top bar menu and notifications toggle. 2017-11-16 07:59:10 +04:00
John Preston
9743dc1ffb Add some more actions to three dot menu. 2017-11-16 07:59:10 +04:00
John Preston
fcf2b9d1a7 Add some more actions to info profile. 2017-11-16 07:59:10 +04:00
John Preston
9f37820901 Add bot Help and Settings buttons in info. 2017-11-16 07:59:09 +04:00
John Preston
4295a823c6 Improve bot About section in info profile. 2017-11-16 07:59:09 +04:00
John Preston
8191ebfc49 Improve peer context menu for info. 2017-11-16 07:59:09 +04:00
John Preston
3fe12f1249 Display verified badge in the info. 2017-11-16 07:59:09 +04:00
John Preston
230c83d218 Follow group->supergroup migration in info. 2017-11-16 07:59:09 +04:00
John Preston
11a3308cf5 Scroll to field on search query update. 2017-11-16 07:59:09 +04:00
John Preston
3992ff6b59 Switch add member and search members buttons. 2017-11-16 07:59:09 +04:00
John Preston
a05c7a815a Fix animation lag in info layer wrap. 2017-11-16 07:59:09 +04:00
John Preston
a7807420fa Fix animation lag in shared media. 2017-11-16 07:59:09 +04:00
John Preston
47a52b0587 Moved several modules from history/ to data/. 2017-11-16 07:59:09 +04:00
John Preston
d67a8a4708 Fix edit bio in Settings. 2017-11-16 07:59:09 +04:00
John Preston
9c01bbca95 Fix invoice amount display. 2017-11-16 07:59:09 +04:00
John Preston
554eb3a342 Move stickers state variables to AuthSessionData.
Also allow to click on the selected set when choosing megagroup
sticker set and allow to paste a t.me link to the set there.
2017-11-16 07:59:09 +04:00
John Preston
9a56b2d20f Move dialogsWidthRatio to AuthSessionData. 2017-11-16 07:59:09 +04:00
John Preston
4771ea7cd4 Display "{from}:" in global search results.
Regression was introduced in c09fbcfeb3.
2017-11-16 07:59:09 +04:00
John Preston
aec496d520 Remove RTL Override symbols from filenames. 2017-11-16 07:59:09 +04:00
John Preston
cb5c59c86c Fix build and crash in Xcode. 2017-11-16 07:59:09 +04:00
John Preston
628c8e10f7 Search and save state in common groups. 2017-11-16 07:59:09 +04:00
John Preston
a6361d6221 Move common_groups info module. 2017-11-16 07:59:08 +04:00
John Preston
39c5898fa4 Save media search state to memento. 2017-11-16 07:59:08 +04:00
John Preston
09d1e3629a Add media search to all info modes. 2017-11-16 07:59:08 +04:00
John Preston
86ad15612a Use Info::Controller for the whole info section. 2017-11-16 07:59:08 +04:00
John Preston
c9152b0b3a Cache media search results until empty query. 2017-11-16 07:59:08 +04:00
John Preston
eb2719fad1 Added search to files and links shared media. 2017-11-16 07:59:08 +04:00
John Preston
a27edcad1c Extract SparseIdsList module from SharedMedia.
This way it can be reused in search results management.
2017-11-16 07:59:08 +04:00
John Preston
15cc4502b4 Save scroll top state to media memento. 2017-11-16 07:59:08 +04:00
John Preston
f6ed3dff7f Rewrite base::lambda_guard, use only one pointer.
Support base::enable_weak_from_this for guarding, not only QObject,
in base::lambda_guard, in App::CallDelayed and in App::LambdaDelayed.

Allow only one guarding pointer, no places in code use more than one.
2017-11-16 07:59:08 +04:00
John Preston
101d4f6444 Use std::function for base::lambda implementation.
base::lambda becomes just std::function and base::lambda_once becomes
base::unique_function - a move-only wrapper around std::function.

This is required because Visual C++ 2017 15.4.1 has a compiler bug
with static member variables of class templates, they may collide.

The std::function uses inheritance and virtual functions instead of
custom vtables done by static members of class templates used in
custom base::lambda implementation, so they work fine.
2017-11-16 07:59:08 +04:00
John Preston
fde3ff1bbf Simplify rpl::consumer. 2017-11-16 07:59:08 +04:00
John Preston
53de44f272 Clear selection after forward in info shared media. 2017-11-16 07:59:08 +04:00
John Preston
f5c5c32d1d Add context menu to info shared media. 2017-11-16 07:59:08 +04:00
John Preston
9a988d89e3 Remove std::any dependency (for now).
Xcode 9 still doesn't have std::any :(
2017-11-16 07:59:08 +04:00
John Preston
b51f865c54 Save info members list state to memento. 2017-11-16 07:59:08 +04:00
John Preston
fb46c33d7f Add context menu support to info members list. 2017-11-16 07:59:07 +04:00
John Preston
856ca22aad Display online count in the info profile section. 2017-11-16 07:59:07 +04:00
John Preston
508fa14385 Workaround render glitches on new MacBooks.
For unknown reason large windows have bad render glitches in High Sierra.
Forcing of OpenGL composition (by adding a fake child QOpenGLWidget) fixes it.
2017-11-16 07:59:07 +04:00
John Preston
5b190c5098 Preserve TopBarOverride in Info WrapWidget.
Also support better selection in info shared media.
Also fix build for Xcode.
2017-11-16 07:59:07 +04:00
John Preston
6b5e06de50 Removed collapsing of shared media. 2017-11-16 07:59:07 +04:00
John Preston
be5f4c9a71 Allow delete / forward selected in shared media.
Also use PeerListBox with a chats list with global search controller
instead of HistoryHider for forward / share contact.
2017-11-16 07:59:07 +04:00
John Preston
7b69282c7e Add rpl::merge(). 2017-11-16 07:59:07 +04:00
John Preston
54cc3e6315 Shared media multiple items selection. 2017-11-16 07:59:07 +04:00
John Preston
66146c382d Improve paths for Xcode build. 2017-11-16 07:59:07 +04:00
John Preston
989f0cc683 Fix build in Xcode. 2017-11-16 07:59:07 +04:00
John Preston
e02d209e6f Fix build with GCC. 2017-11-16 07:59:07 +04:00
John Preston
6445c0563e Fix reading from freed memory in rpl::take(). 2017-11-16 07:59:07 +04:00
John Preston
583b0fa778 Display common groups in Info profiles. 2017-11-16 07:59:07 +04:00
John Preston
fee517384c Disable round videos in shared media for now. 2017-11-16 07:59:07 +04:00
John Preston
aa260d263b Don't forget current item in MediaView. 2017-11-16 07:59:07 +04:00
John Preston
a08dd1f6e1 Fix build for macOS. 2017-11-16 07:59:06 +04:00
John Preston
f107866b42 Add basic click handler support to info shared media. 2017-11-16 07:59:06 +04:00
John Preston
7f3c97fb01 Add info media preloading to both sides. 2017-11-16 07:59:06 +04:00
John Preston
65cc4d3fbc Support item repaint in Info media overview. 2017-11-16 07:59:06 +04:00
John Preston
fdd89d65ca Allow using custom comparators in flat_[map|set]. 2017-11-16 07:59:06 +04:00
John Preston
ecbc0ae57e Show info media overview using Overview::Layout. 2017-11-16 07:59:06 +04:00
John Preston
7905694b31 Add tabs and other types links to Info::Media. 2017-11-16 07:59:06 +04:00
John Preston
335704e176 Fix layer resize animation glitches. 2017-11-16 07:59:06 +04:00
John Preston
c0bb8a8af7 Return third section when returning in main section. 2017-11-16 07:59:06 +04:00
John Preston
76b8078bd9 Save section expand state in Info memento. 2017-11-16 07:59:06 +04:00
John Preston
c6c75a1980 Animate Info-to-Info transitions. 2017-11-16 07:59:06 +04:00
John Preston
93c15e5ee6 Use internal section stack in Info::WrapWidget. 2017-11-16 07:59:06 +04:00
John Preston
525cde3498 Use make_state for flatten_latest(). 2017-11-16 07:59:06 +04:00
John Preston
c4d33f9986 Add rpl::take(count). 2017-11-16 07:59:06 +04:00
John Preston
f0ad78d808 Change *[Fast|Animated] to anim::type in SlideWrap. 2017-11-16 07:59:06 +04:00
John Preston
83850d9b86 Change *[Fast|Animated] to anim::type in FadeWrap. 2017-11-16 07:59:06 +04:00
John Preston
0c4bda71fd Remove some unused / rare phrases. 2017-11-16 07:59:05 +04:00
John Preston
d1687ab963 Improve info wrapping in section / layer.
Also move layerwidget to window/layer_widget.
Also replace ui/effects/widget_fade_wrap with ui/wrap/fade_wrap.
2017-11-16 07:59:05 +04:00
John Preston
ea0f6b9a12 Use 'if constexpr ()' instead of tag dispatch. 2017-11-16 07:59:05 +04:00
John Preston
5cc7cb1d85 Allow empty arg list in rpl next/error handlers. 2017-11-16 07:59:05 +04:00
John Preston
21b1ba1f88 Move build to Ubuntu 14.04 and GCC 7.2.
To be able to run on the same distributions as before we need to have
the same GLIBC version dependency as in Ubuntu 12.04, which is 2.15.

For that we need to remove all usages of GLIBC features from 2.16 and above.
Currently there are three methods used, so they're wrapped in a separate
static library, linux_glibc_wraps.

It is a separate library because it must be compiled without '-flto' flag,
otherwise the inline __asm__ is not working and we get unresolved symbols.
2017-11-16 07:59:05 +04:00
John Preston
1cd126d728 Disable not type-erased consumers on GCC. 2017-11-16 07:59:05 +04:00
John Preston
6861059d18 Fix build for old OS X with Qt 5.3.2 2017-11-16 07:59:05 +04:00
John Preston
80d9938e96 Support and use not type-erased consumers. 2017-11-16 07:59:05 +04:00
John Preston
fddcdf359b Use not type-erased producers in code. 2017-11-16 07:59:05 +04:00
John Preston
cdda7f8f9a Allow not type-erased producers. 2017-11-16 07:59:05 +04:00
John Preston
086e46c162 Add and use only rpl::start_with_*() methods. 2017-11-16 07:59:05 +04:00
John Preston
ed061252a5 Move to Xcode 9.0 and fix errors in Clang build. 2017-11-16 07:59:05 +04:00
John Preston
7c4e4d7fa2 Closed beta 1.1.23.1. 2017-11-16 07:59:05 +04:00
John Preston
4180ed09a5 Add user actions to info profile. 2017-11-16 07:59:05 +04:00
John Preston
f50bf0b97f Show old overview / common groups for now. 2017-11-16 07:59:05 +04:00
John Preston
2c75b4836d Improve sorting by online in info profile. 2017-11-16 07:59:05 +04:00
John Preston
292e57ffc7 Use PeerListBox content in info profile. 2017-11-16 07:59:04 +04:00
John Preston
1a0e524b49 Optimize third column (create it only once).
Before historyPeer and historyPeerCanWrite were independent, so we
created a new Info section for both of them changing.

Now we use Data::CanWriteValue(peer) and rpl::flatten_latest().
2017-11-16 07:59:04 +04:00
John Preston
ffc20e4492 Divide structs into several data/ modules. 2017-11-16 07:59:04 +04:00
John Preston
f2a5862714 Add members list to info profile. 2017-11-16 07:59:04 +04:00
John Preston
faeb1483f2 Divide info_profile_lines in different modules. 2017-11-16 07:59:04 +04:00
John Preston
a4c2138e74 Finalize move of info-profile modules. 2017-11-16 07:59:04 +04:00
John Preston
1c5d410373 Move info-profile modules to info/profile/
Next commit fixes the build.
2017-11-16 07:59:04 +04:00
John Preston
b9fb9af74f Info shared media and common groups counters. 2017-11-16 07:59:04 +04:00
John Preston
812dcb5e8d Update styles to match the design. 2017-11-16 07:59:04 +04:00
John Preston
703b944839 Return FlatLabel.margins in getMargins(). 2017-11-16 07:59:04 +04:00
John Preston
e1ba9f8ff8 Hide send message in Info for current chat. 2017-11-16 07:59:04 +04:00
John Preston
3db696d52f Add rpl::combine_previous() operator. 2017-11-16 07:59:04 +04:00
John Preston
6d0dbebda9 Fix tabbed selector section / panel exchange. 2017-11-16 07:59:04 +04:00
John Preston
f4d9618487 Improve layer / section exchange for Info. 2017-11-16 07:59:04 +04:00
John Preston
b7077eb71d Enable third column info by default. 2017-11-16 07:59:03 +04:00
John Preston
1a4d326abb Show Info if writing is forbidden. 2017-11-16 07:59:03 +04:00
John Preston
48cbdd9d40 Don't toggle tabbed section from OneColumn. 2017-11-16 07:59:03 +04:00
John Preston
26532ab9b4 Fix small chats list column bug with boxes. 2017-11-16 07:59:03 +04:00
John Preston
c0e780a28f Allow small dialogs list with three columns. 2017-11-16 07:59:03 +04:00
John Preston
5c4daeee4c Add rpl::variable, improve filter / combine. 2017-11-16 07:59:03 +04:00
John Preston
1c5abaa518 Remove mutex locks from rpl for now. 2017-11-16 07:59:03 +04:00
John Preston
5586d231de Switch Info between columns and layer. 2017-11-16 07:59:03 +04:00
John Preston
3fbb643d51 GCC bug workaround.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67274
2017-11-16 07:59:03 +04:00
John Preston
766e7dadb1 Use improved rpl::start(). 2017-11-16 07:59:03 +04:00
John Preston
ee9763c98f Improve rpl::combine() and rpl::start(). 2017-11-16 07:59:03 +04:00
John Preston
5e7aa4ff81 Move third column from HistoryWidget to MainWidget. 2017-11-16 07:59:03 +04:00
John Preston
f162462111 Move info between Layer and Narrow wrap. 2017-11-16 07:59:03 +04:00
John Preston
088d23d557 Start new Info section (profile + shared media). 2017-11-16 07:59:02 +04:00
John Preston
fbcd5e2f1e Try to use const-ref better in rpl. 2017-11-16 07:59:02 +04:00
John Preston
c302219f9e Use rpl in some widgets and effects. 2017-11-16 07:59:02 +04:00
John Preston
21d136e224 myEnsureResized() now forces recursive create. 2017-11-16 07:59:02 +04:00
John Preston
487ddb5694 Add some rpl operators. 2017-11-16 07:59:02 +04:00
John Preston
873ccf8096 Implement SharedMediaWithLastViewer using rpl. 2017-11-16 07:59:02 +04:00
John Preston
696478843e Implement UserPhotosViewer using rpl. 2017-11-16 07:59:02 +04:00
John Preston
2690618da2 Add Storage::UserPhotos and UserPhotosSlice. 2017-11-16 07:59:02 +04:00
John Preston
68a0e32a3d Add SharedMediaSliceWithLast for chat photos. 2017-11-16 07:59:02 +04:00
John Preston
449986456e Add SharedMediaSliceMerged for migrated histories. 2017-11-16 07:59:02 +04:00
John Preston
2363a6bd44 Add SharedMediaSlice to observe shared media.
Start testing / using it in MediaView.
2017-11-16 07:59:02 +04:00
John Preston
41ed2d1b84 New storage for shared media messages index. 2017-11-16 07:59:02 +04:00
John Preston
b873fee1cf Use rvalue references in rpl next / error. 2017-11-16 07:59:01 +04:00
John Preston
e70052e966 Add piping and on_next, on_error, on_done, start. 2017-11-16 07:59:01 +04:00
John Preston
101fdb1fba Add event_stream for events with many consumers. 2017-11-16 07:59:01 +04:00
John Preston
ebe4bbbf0f Add core rpl::producer/consumer implementation. 2017-11-16 07:59:01 +04:00
Roman Voropaev
63669c1612 Added cmake to %PATH% (#4066)
It's later used in OpenAL building.
2017-11-15 21:16:44 +01:00
John Preston
1c8db1e2e9 Fix travis build for the latest ffmpeg code. 2017-11-13 13:55:11 +04:00
Christoph
62463d2c3e Remove notes about the signature (#4015)
* Remove notes about the signature

It's handled by a bot now 🎉

* Remove check from travis

* Remove check from appveyor
2017-10-26 23:35:55 +02:00
John Preston
247f8f4fcc Fix instructions markup. 2017-10-11 22:33:49 +01:00
Duncan Ogilvie
34d15e7216 don't call vcvarsall.bat in AppVeyor script (#3945)
Follow-up for #3920

Signed-off-by: Duncan Ogilvie mr.exodia.tpodt@gmail.com (github: mrexodia)
2017-09-29 20:24:04 +02:00
John Preston
d46a5f693f Remove unused lang phrases and some code. 2017-09-28 19:18:27 +03:00
eegorov
8bfe407610 New build option: without GTK and appindicator
Signed-off-by: Egor Y. Egorov <egor.y.egorov@gmail.com> (github: eegorov)
2017-09-28 18:32:51 +03:00
visuve
08e3a54a58 Mark missing ctors deleted
- Satisfy the rule of five

Signed-off-by: Veli-Matti Visuri <veli-matti.visuri@cerescon.fi> (github: visuve)
2017-09-28 18:23:42 +03:00
visuve
8c92f42de3 Fix uninitialized values
- Use C++11 default member initializers

Signed-off-by: Veli-Matti Visuri <veli-matti.visuri@cerescon.fi> (github: visuve)
2017-09-28 18:23:42 +03:00
Alexander GQ Gerasiov
07106897a6 Fix CVE-2016-10351: Insecure cWorkingDir permissions.
Set 700 permisson on dir on every start.

Signed-off-by: Alexander GQ Gerasiov <gq@cs.msu.su>
2017-09-28 18:19:27 +03:00
Duncan Ogilvie
5d5b89c82d Customized BUILD_DIR in install.bat (#3920)
This is a very simple change that allow people to build Telegram like AppVeyor does it, but not in C:\TBuild (often C is "System Reserved" and cannot be used). Instead you can build it anywhere (from the visual studio 2017 x86 command prompt) like this:

    >set BUILD_DIR=%CD%
    >git clone https://github.com/telegramdesktop/tdesktop.git
    >cd tdesktop
    >.\.appveyor\install.bat
    >msbuild Telegram\Telegram.sln /property:Configuration=Debug /p:Platform=Win32

Some notes:

- I replaced all C:\TBuild with %BUILD_DIR%, even if it is decided not to merge this, keep that.
- %BUILD_DIR%\Libraries\prepare.bat might fail to extract the 7z Qt libraries for some reason (even if 7z.exe is in PATH) this has not been fixed

Signed-off-by: Duncan Ogilvie mr.exodia.tpodt@gmail.com (github: mrexodia)
2017-09-28 12:03:39 +02:00
Jan Niklas Hasse
e42cc02d0e Prefer AppIndicator if DBus interface is available
Starting with Ubuntu 17.10 the interface will be provided by an
extension (shipped by default):

https://github.com/ubuntu/gnome-shell-extension-appindicator

Legacy tray icons have been completely removed in GNOME 3.26. By
checking the interface, this will allow users of other distributions
with GNOME to also use Telegram's indicator with the extension.

Signed-off-by: Jan Niklas Hasse <jhasse@bixense.com> (github: jhasse)
2017-09-28 12:59:46 +03:00
Yonsh Lin
11a46a1072 Fix IME being interrupted after reconnection
Signed-off-by: Yonsh Lin <yonsh@live.com> (github: yonsh)
2017-09-28 12:57:25 +03:00
Monote
a0fbbf2fb6 Fix build instructions for MSVC (#3878)
Fixed 'change directory' commands for following build process step-by-step.

Signed-off-by: Andrew Aponte <coyshibe@gmail.com> (github: monote)
2017-09-11 14:04:25 +03:00
John Preston
74e46f7b80 Fix travis / appveyor CI builds. 2017-09-06 17:12:26 +03:00
John Preston
b8d1b8d6c1 Update build docs for VS 2017.
Closes #3117. Closes #3729.
2017-09-06 17:11:30 +03:00
John Preston
7ae1ef0a1a Migrate to VS2017. 2017-09-06 17:11:06 +03:00
John Preston
13aa42c883 Use GYP rule for Qt MOC only on Telegram project. 2017-09-06 12:12:04 +03:00
645 changed files with 54642 additions and 57068 deletions

View File

@@ -1,30 +0,0 @@
@echo off
call:checkCommitMessage
GOTO:EOF
:checkCommitMessage
call:logInfo "Commit message: %APPVEYOR_REPO_COMMIT_MESSAGE%"
call:logInfo "Is pull request: %APPVEYOR_PULL_REQUEST_NUMBER%"
if not "%APPVEYOR_PULL_REQUEST_NUMBER%" == "" (
ECHO "%APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED%" | FINDSTR /C:"Signed-off-by: " >nul & IF ERRORLEVEL 1 (
call:logError "The commit message does not contain the signature!"
call:logError "More information: https://github.com/telegramdesktop/tdesktop/blob/master/.github/CONTRIBUTING.md#sign-your-work"
exit 1
) else (
call:logInfo "Commit message contains signature"
:: Reset error level
verify >nul
)
)
GOTO:EOF
:logInfo
echo [INFO] %~1
GOTO:EOF
:logError
echo [ERROR] %~1
GOTO:EOF

View File

@@ -1,12 +1,10 @@
@echo off
SET BUILD_DIR=C:\TBuild
IF "%BUILD_DIR%"=="" SET BUILD_DIR=C:\TBuild
SET LIB_DIR=%BUILD_DIR%\Libraries
SET SRC_DIR=%BUILD_DIR%\tdesktop
SET QT_VERSION=5_6_2
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
call:configureBuild
call:getDependencies
call:setupGYP
@@ -29,7 +27,7 @@ GOTO:EOF
call:logInfo "Clone dependencies repository"
git clone -q --depth 1 --branch=master https://github.com/telegramdesktop/dependencies_windows.git %LIB_DIR%
cd %LIB_DIR%
git clone https://github.com/Microsoft/Range-V3-VS2015 range-v3
if exist prepare.bat (
call prepare.bat
) else (
@@ -45,7 +43,7 @@ GOTO:EOF
git clone https://chromium.googlesource.com/external/gyp
cd gyp
git checkout a478c1ab51
SET PATH=%PATH%;C:\TBuild\Libraries\gyp;C:\TBuild\Libraries\ninja;
SET PATH=%PATH%;%BUILD_DIR%\Libraries\gyp;%BUILD_DIR%\Libraries\ninja;
cd %SRC_DIR%
git submodule init
git submodule update
@@ -82,6 +80,10 @@ GOTO:EOF
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_UNITY_INTEGRATION
)
echo %BUILD_VERSION% | findstr /C:"disable_gtk_integration">nul && (
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_GTK_INTEGRATION
)
if not "%TDESKTOP_BUILD_DEFINES%" == "" (
set "TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES:~1%"
)

View File

@@ -5,8 +5,6 @@ This document describes how you can contribute to Telegram Desktop. Please read
**Table of Contents**
* [What contributions are accepted](#what-contributions-are-accepted)
* [Sign your work](#sign-your-work)
* [Change commit message of a pushed commit](#change-commit-message-of-a-pushed-commit)
* [Build instructions](#build-instructions)
* [Pull upstream changes into your fork regularly](#pull-upstream-changes-into-your-fork-regularly)
* [How to get your pull request accepted](#how-to-get-your-pull-request-accepted)
@@ -28,49 +26,6 @@ Unfortunately we **do not merge** any pull requests that have new feature implem
Telegram Desktop is not a standalone application but a part of [Telegram project][telegram], so all the decisions about the features, languages, user experience, user interface and the design are made inside Telegram team, often according to some roadmap which is not public.
## Sign your work
For contributions to be accepted they should be granted into the public domain. This will solve the issue if Telegram team needs to use full Telegram Desktop source code with some different license.
The sign-off is a simple line at the end of the explanation for the patch. Your signature certifies that you wrote the patch and you have the right to put it in the public domain. The rules are pretty simple: if you can certify the below:
```
Telegram Desktop Developer Certificate of Origin
By making a contribution to this project, I certify that:
(a) The contribution was created in whole by me or is based upon
previous work that, to the best of my knowledge, is in the
public domain and I have the right to put it in the public domain.
(d) I understand and agree that this project and the contribution are
public and that a record of the contribution (including all
metadata and personal information I submit with it, including my
sign-off) is maintained indefinitely and may be redistributed.
(e) I am granting this work into the public domain.
```
Then you just add a line to every **git commit message** that states:
Signed-off-by: Random J Developer <random@developer.example.org> (github: rndjdev_github)
Replacing Random Developers details with your name, email address and GitHub username.
### Change commit message of a pushed commit
If you already pushed a commit and forgot to add the signature to the commit message, follow these steps to change the message of the commit:
1. Open `Git Bash` (or `Git Shell`)
2. Enter following command to change the commit message of the most recent commit: `git commit --amend`
3. Press <kbd>i</kbd> to get into Insert-mode
4. Change the commit message (and add the [signature](#sign-your-work) at the and)
5. After editing the message, press <kbd>ESC</kbd> to get out of the Insert-mode
6. Write `:wq` and press <kbd>Enter</kbd> to save the new message or write `:q!` to discard your changes
7. Enter `git push --force` to push the commit with the new commit message to the remote repository
For more info, see [GitHub Help][help_change_commit_message].
## Build instructions
See the [README.md][build_instructions] for details on the various build
@@ -118,7 +73,7 @@ If you already have multiple commits, you can add the commits together (squash t
1. Open `Git Bash` (or `Git Shell`)
2. Enter following command to squash the recent {N} commits: `git reset --soft HEAD~{N} && git commit` (replace `{N}` with the number of commits you want to squash)
3. Press <kbd>i</kbd> to get into Insert-mode
4. Enter the commit message of the new commit (and add the [signature](#sign-your-work) at the end)
4. Enter the commit message of the new commit
5. After adding the message, press <kbd>ESC</kbd> to get out of the Insert-mode
6. Write `:wq` and press <kbd>Enter</kbd> to save the new message or write `:q!` to discard your changes
7. Enter `git push --force` to push the new commit to the remote repository
@@ -150,8 +105,6 @@ Before you submit a pull request, please test your changes. Verify that Telegram
For example: `Fix #545`
* Don't forget to [sign your patch](#sign-your-work) to put it in the public domain!
[//]: # (LINKS)
[telegram]: https://telegram.org/
[help_fork_repo]: https://help.github.com/articles/fork-a-repo/

1
.gitignore vendored
View File

@@ -34,6 +34,7 @@
*.xcodeproj
/Win32/
ipch/
.vs/
/Telegram/log.txt
/Telegram/data

View File

@@ -16,6 +16,7 @@ env:
- BUILD_VERSION="disable_network_proxy"
- BUILD_VERSION="disable_desktop_file_generation"
- BUILD_VERSION="disable_unity_integration"
- BUILD_VERSION="disable_gtk_integration"
matrix:
fast_finish: true
@@ -32,8 +33,8 @@ addons:
- dpatch
- equivs
- fakeroot
- g++-6
- gcc-6
- g++-7
- gcc-7
- git
- gnome-common
- gobject-introspection
@@ -57,10 +58,8 @@ addons:
- yasm
before_install:
- "export TRAVIS_COMMIT_MSG=\"$(git log --format=%B --no-merges -n 1)\""
- .travis/check.sh
- export CXX="g++-6" CC="gcc-6"
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-6
- export CXX="g++-7" CC="gcc-7"
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-7
- sudo update-alternatives --config gcc
- g++ --version

View File

@@ -27,6 +27,9 @@ GYP_PATH="$BUILD/gyp"
GYP_CACHE_VERSION="3"
GYP_PATCH="$UPSTREAM/Telegram/Patches/gyp.diff"
RANGE_PATH="$BUILD/range-v3"
RANGE_CACHE_VERSION="3"
VA_PATH="$BUILD/libva"
VA_CACHE_VERSION="3"
@@ -85,6 +88,9 @@ build() {
# Patched GYP (supports cmake precompiled headers)
getGYP
# Range v3
getRange
# Guideline Support Library
getGSL
@@ -118,6 +124,10 @@ build() {
GYP_DEFINES+=",TDESKTOP_DISABLE_UNITY_INTEGRATION"
fi
if [[ $BUILD_VERSION == *"disable_gtk_integration"* ]]; then
GYP_DEFINES+=",TDESKTOP_DISABLE_GTK_INTEGRATION"
fi
info_msg "Build defines: ${GYP_DEFINES}"
buildTelegram
@@ -174,6 +184,52 @@ buildXkbCommon() {
sudo ldconfig
}
getRange() {
travisStartFold "Getting range-v3"
local RANGE_CACHE="$CACHE/range-v3"
local RANGE_CACHE_FILE="$RANGE_CACHE/.cache.txt"
local RANGE_CACHE_KEY="${RANGE_CACHE_VERSION}"
local RANGE_CACHE_OUTDATED="1"
if [ ! -d "$RANGE_CACHE" ]; then
mkdir -p "$RANGE_CACHE"
fi
ln -sf "$RANGE_CACHE" "$RANGE_PATH"
if [ -f "$RANGE_CACHE_FILE" ]; then
local RANGE_CACHE_KEY_FOUND=`tail -n 1 $RANGE_CACHE_FILE`
if [ "$RANGE_CACHE_KEY" == "$RANGE_CACHE_KEY_FOUND" ]; then
RANGE_CACHE_OUTDATED="0"
else
info_msg "Cache key '$RANGE_CACHE_KEY_FOUND' does not match '$RANGE_CACHE_KEY', getting range-v3"
fi
fi
if [ "$RANGE_CACHE_OUTDATED" == "1" ]; then
buildRange
sudo echo $RANGE_CACHE_KEY > "$RANGE_CACHE_FILE"
else
info_msg "Using cached range-v3"
fi
}
buildRange() {
info_msg "Downloading range-v3"
if [ -d "$EXTERNAL/range-v3" ]; then
rm -rf "$EXTERNAL/range-v3"
fi
cd $RANGE_PATH
rm -rf *
cd "$EXTERNAL"
git clone --depth=1 https://github.com/ericniebler/range-v3
cd "$EXTERNAL/range-v3"
cp -r * "$RANGE_PATH/"
}
getVa() {
travisStartFold "Getting libva"
@@ -315,6 +371,8 @@ buildFFmpeg() {
git clone https://git.ffmpeg.org/ffmpeg.git
cd "$EXTERNAL/ffmpeg"
git checkout release/3.4
./configure \
--prefix=$FFMPEG_PATH \
--disable-debug \
@@ -542,6 +600,11 @@ buildCustomQt() {
git apply "$QT_PATCH"
cd ..
cd "$EXTERNAL/qt${QT_VERSION}/qtbase/src/plugins/platforminputcontexts"
git clone https://github.com/telegramdesktop/fcitx.git
git clone https://github.com/telegramdesktop/hime.git
cd ../../../..
./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 \
@@ -617,6 +680,7 @@ buildTelegram() {
-Dlinux_path_vdpau=$VDPAU_PATH \
-Dlinux_path_ffmpeg=$FFMPEG_PATH \
-Dlinux_path_openal=$OPENAL_PATH \
-Dlinux_path_range=$RANGE_PATH \
-Dlinux_path_qt=$QT_PATH \
-Dlinux_path_breakpad=$BREAKPAD_PATH \
-Dlinux_path_libexif_lib=/usr/local/lib \

View File

@@ -1,25 +0,0 @@
#!/bin/bash
# Checks if the commit message contains the signature
run() {
checkCommitMessage
}
checkCommitMessage() {
info_msg "Commit message: ${TRAVIS_COMMIT_MSG}";
info_msg "Is pull request: ${TRAVIS_PULL_REQUEST}";
if [[ $TRAVIS_PULL_REQUEST != "false" ]];then
if [[ $TRAVIS_COMMIT_MSG != *"Signed-off-by: "* ]];then
error_msg "The commit message does not contain the signature!"
error_msg "More information: https://github.com/telegramdesktop/tdesktop/blob/master/.github/CONTRIBUTING.md#sign-your-work"
exit 1
else
success_msg "Commit message contains signature"
fi
fi
}
source ./.travis/common.sh
run

View File

@@ -35,14 +35,15 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* FFmpeg ([LGPL](https://www.ffmpeg.org/legal.html))
* Guideline Support Library ([MIT License](https://github.com/Microsoft/GSL/blob/master/LICENSE))
* Mapbox Variant ([BSD License](https://github.com/mapbox/variant/blob/master/LICENSE))
* Range-v3 ([Boost License](https://github.com/ericniebler/range-v3/blob/master/LICENSE.txt))
* Open Sans font ([Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html))
* Emoji alpha codes ([MIT License](https://github.com/emojione/emojione/blob/master/extras/alpha-codes/LICENSE.md))
* Catch test framework ([Boost License](https://github.com/philsquared/Catch/blob/master/LICENSE.txt))
## Build instructions
* [Visual Studio 2015][msvc]
* [Xcode 8][xcode]
* [Visual Studio 2017][msvc]
* [Xcode 9][xcode]
* [GYP/CMake on GNU/Linux][cmake]
[//]: # (LINKS)

View File

@@ -1,5 +1,17 @@
diff --git a/src/build/common.gypi b/src/build/common.gypi
index 29990c6..53e99d4 100644
--- a/src/build/common.gypi
+++ b/src/build/common.gypi
@@ -330,6 +330,7 @@
'VCCLCompilerTool': {
'WarnAsError': 'true',
'Detect64BitPortabilityProblems': 'false',
+ 'TreatWChar_tAsBuiltInType': 'false',
},
},
}],
diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
index 584ec5d..1c7214f 100644
index 1a93ce6..1c1d643 100644
--- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj
+++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
@@ -35,6 +35,19 @@
@@ -77,7 +89,7 @@ index 584ec5d..1c7214f 100644
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -715,7 +703,6 @@
@@ -714,7 +702,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -85,7 +97,7 @@ index 584ec5d..1c7214f 100644
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1183,18 +1170,13 @@
@@ -1181,18 +1168,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */;
buildPhases = (
@@ -104,7 +116,7 @@ index 584ec5d..1c7214f 100644
);
name = Breakpad;
productInstallPath = "$(HOME)/Library/Frameworks";
@@ -1401,6 +1383,8 @@
@@ -1399,6 +1381,8 @@
/* Begin PBXProject section */
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
@@ -113,7 +125,7 @@ index 584ec5d..1c7214f 100644
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "Breakpad" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
@@ -1585,16 +1569,6 @@
@@ -1583,16 +1567,6 @@
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
@@ -130,7 +142,7 @@ index 584ec5d..1c7214f 100644
F92C569C0ECE04A7009BE4BA /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -1642,20 +1616,6 @@
@@ -1640,20 +1614,6 @@
shellPath = /bin/sh;
shellScript = "install_name_tool -id \"@executable_path/../Resources/breakpadUtilities.dylib\" \"${BUILT_PRODUCTS_DIR}/breakpadUtilities.dylib\"\n";
};
@@ -151,7 +163,7 @@ index 584ec5d..1c7214f 100644
F9C77DD80F7DD5CF0045F7DB /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1676,6 +1636,19 @@
@@ -1674,6 +1634,19 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -171,7 +183,7 @@ index 584ec5d..1c7214f 100644
F92C565F0ECD116B009BE4BA /* protected_memory_allocator.cc in Sources */,
F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */,
F92C55D10ECD0064009BE4BA /* Breakpad.mm in Sources */,
@@ -1957,16 +1930,6 @@
@@ -1955,16 +1928,6 @@
target = F92C563B0ECD10B3009BE4BA /* breakpadUtilities */;
targetProxy = F92C564D0ECD10E5009BE4BA /* PBXContainerItemProxy */;
};
@@ -188,7 +200,7 @@ index 584ec5d..1c7214f 100644
F93DE2FC0F82C3C600608B94 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F93803BD0F80820F004D428B /* generator_test */;
@@ -2027,11 +1990,6 @@
@@ -2025,11 +1988,6 @@
target = 8DC2EF4F0486A6940098B216 /* Breakpad */;
targetProxy = F9C44E190EF0790F003AEBAA /* PBXContainerItemProxy */;
};
@@ -200,7 +212,7 @@ index 584ec5d..1c7214f 100644
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -2128,8 +2086,12 @@
@@ -2126,8 +2084,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */;
buildSettings = {
@@ -214,7 +226,7 @@ index 584ec5d..1c7214f 100644
};
name = Debug;
};
@@ -2137,7 +2099,12 @@
@@ -2135,7 +2097,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 8B31027811F0D3AF00FCF3E4 /* BreakpadRelease.xcconfig */;
buildSettings = {
@@ -227,7 +239,7 @@ index 584ec5d..1c7214f 100644
};
name = Release;
};
@@ -2456,7 +2423,12 @@
@@ -2454,7 +2421,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */;
buildSettings = {
@@ -467,3 +479,151 @@ index 1d2e519..943310f 100644
return true;
}
diff --git a/src/common/language.cc b/src/common/language.cc
index 978fb85..a95ae5f 100644
--- a/src/common/language.cc
+++ b/src/common/language.cc
@@ -46,8 +46,27 @@
#include <limits>
+#include <cstdio>
+#include <iostream>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <array>
+
namespace {
+std::string exec(std::string cmd) {
+ std::array<char, 128> buffer;
+ std::string result;
+ std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
+ if (!pipe) throw std::runtime_error("popen() failed!");
+ while (!feof(pipe.get())) {
+ if (fgets(buffer.data(), 128, pipe.get()) != nullptr)
+ result += buffer.data();
+ }
+ return result;
+}
+
string MakeQualifiedNameWithSeparator(const string& parent_name,
const char* separator,
const string& name) {
@@ -79,11 +98,29 @@ class CPPLanguage: public Language {
demangled->clear();
return kDontDemangle;
#else
+ DemangleResult result;
+ if (mangled.find("type_erased_handlers") != std::string::npos
+ && mangled.find("vtable_once_impl") != std::string::npos) {
+
+ auto demangled_str = exec("c++filt " + mangled);
+ if (!demangled_str.empty() && demangled_str.back() == '\n') {
+ demangled_str.pop_back();
+ }
+ if (demangled_str != mangled) {
+ result = kDemangleSuccess;
+ demangled->assign(demangled_str.c_str());
+ } else {
+ result = kDemangleFailure;
+ demangled->clear();
+ }
+
+ } else {
+
int status;
char* demangled_c =
abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
- DemangleResult result;
+// DemangleResult result;
if (status == 0) {
result = kDemangleSuccess;
demangled->assign(demangled_c);
@@ -96,6 +133,8 @@ class CPPLanguage: public Language {
free(reinterpret_cast<void*>(demangled_c));
}
+ }
+
return result;
#endif
}
diff --git a/src/common/linux/elf_symbols_to_module.cc b/src/common/linux/elf_symbols_to_module.cc
index 562875e..4367851 100644
--- a/src/common/linux/elf_symbols_to_module.cc
+++ b/src/common/linux/elf_symbols_to_module.cc
@@ -39,6 +39,29 @@
#include "common/byte_cursor.h"
#include "common/module.h"
+#include <cstdio>
+#include <iostream>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <array>
+
+namespace {
+
+std::string exec(std::string cmd) {
+ std::array<char, 128> buffer;
+ std::string result;
+ std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
+ if (!pipe) throw std::runtime_error("popen() failed!");
+ while (!feof(pipe.get())) {
+ if (fgets(buffer.data(), 128, pipe.get()) != nullptr)
+ result += buffer.data();
+ }
+ return result;
+}
+
+}
+
namespace google_breakpad {
class ELFSymbolIterator {
@@ -159,6 +182,19 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section,
Module::Extern *ext = new Module::Extern(iterator->value);
ext->name = SymbolString(iterator->name_offset, strings);
#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
+ if (ext->name.find("type_erased_handlers") != std::string::npos
+ && ext->name.find("vtable_once_impl") != std::string::npos) {
+
+ auto demangled_str = exec("c++filt " + ext->name);
+ if (!demangled_str.empty() && demangled_str.back() == '\n') {
+ demangled_str.pop_back();
+ }
+ if (demangled_str != ext->name) {
+ ext->name = demangled_str;
+ }
+
+ } else {
+
int status = 0;
char* demangled =
abi::__cxa_demangle(ext->name.c_str(), NULL, NULL, &status);
@@ -167,6 +203,8 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section,
ext->name = demangled;
free(demangled);
}
+
+ }
#endif
module->AddExtern(ext);
}
diff --git a/src/tools/linux/tools_linux.gypi b/src/tools/linux/tools_linux.gypi
index 1c15992..020e4c1 100644
--- a/src/tools/linux/tools_linux.gypi
+++ b/src/tools/linux/tools_linux.gypi
@@ -58,7 +58,7 @@
'target_name': 'minidump_upload',
'type': 'executable',
'sources': [
- 'symupload/minidump_upload.m',
+ 'symupload/minidump_upload.cc',
],
'dependencies': [
'../common/common.gyp:common',

View File

@@ -0,0 +1,18 @@
set -e
FullExecPath=$PWD
pushd `dirname $0` > /dev/null
FullScriptPath=`pwd`
popd > /dev/null
pacman --noconfirm -Sy
pacman --noconfirm -S msys/make
pacman --noconfirm -S mingw64/mingw-w64-x86_64-opus
pacman --noconfirm -S diffutils
pacman --noconfirm -S pkg-config
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
./configure --toolchain=msvc --disable-programs --disable-doc --disable-everything --enable-protocol=file --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wavpack --enable-decoder=opus --enable-decoder=pcm_alaw --enable-decoder=pcm_alaw_at --enable-decoder=pcm_f32be --enable-decoder=pcm_f32le --enable-decoder=pcm_f64be --enable-decoder=pcm_f64le --enable-decoder=pcm_lxf --enable-decoder=pcm_mulaw --enable-decoder=pcm_mulaw_at --enable-decoder=pcm_s16be --enable-decoder=pcm_s16be_planar --enable-decoder=pcm_s16le --enable-decoder=pcm_s16le_planar --enable-decoder=pcm_s24be --enable-decoder=pcm_s24daud --enable-decoder=pcm_s24le --enable-decoder=pcm_s24le_planar --enable-decoder=pcm_s32be --enable-decoder=pcm_s32le --enable-decoder=pcm_s32le_planar --enable-decoder=pcm_s64be --enable-decoder=pcm_s64le --enable-decoder=pcm_s8 --enable-decoder=pcm_s8_planar --enable-decoder=pcm_u16be --enable-decoder=pcm_u16le --enable-decoder=pcm_u24be --enable-decoder=pcm_u24le --enable-decoder=pcm_u32be --enable-decoder=pcm_u32le --enable-decoder=pcm_u8 --enable-decoder=pcm_zork --enable-decoder=vorbis --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_d3d11va --enable-hwaccel=h264_dxva2 --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-ldflags="-libpath:$FullExecPath/../opus/win32/VS2015/Win32/Release"
make -j4
make -j4 install

File diff suppressed because it is too large Load Diff

View File

@@ -78,6 +78,9 @@ slideDuration: 240;
slideShift: 100px;
slideShadow: icon {{ "slide_shadow", slideFadeOutShadowFg }};
slideWrapDuration: 150;
fadeWrapDuration: 200;
linkCropLimit: 360px;
linkFont: normalFont;
linkOverFont: font(fsize underline);
@@ -288,7 +291,7 @@ inlineRowBorder: 1px;
inlineRowBorderFg: shadowFg;
inlineRowFileNameTop: 2px;
inlineRowFileDescriptionTop: 23px;
inlineResultsMinWidth: 64px;
inlineResultsMinWidth: 48px;
inlineDurationMargin: 3px;
toastTextStyle: defaultTextStyle;

View File

@@ -316,6 +316,7 @@ historyPeer8NameFg: #ce671b; // orange group member name
historyPeer8NameFgSelected: historyPeer8NameFg; // orange group member name in a selected message
historyPeer8UserpicBg: #faa774; // orange userpic background
historyPeerUserpicFg: windowFgActive; // default userpic initials
historyPeerSavedMessagesBg: historyPeer4UserpicBg; // saved messages userpic background
// Some values are marked as (adjusted), it means they're adjusted by
// hue and saturation of the average background color if user chooses

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

View File

@@ -19,14 +19,13 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
"lng_language_name" = "English";
"lng_switch_to_this" = "Switch to English";
"lng_switch_to_this" = "Continue in English";
"lng_menu_contacts" = "Contacts";
"lng_menu_calls" = "Calls";
"lng_menu_settings" = "Settings";
"lng_menu_about" = "About";
"lng_menu_update" = "Update";
"lng_menu_restart" = "Restart";
"lng_menu_back" = "Back";
"lng_menu_night_mode" = "Night mode";
@@ -71,14 +70,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_weekday6" = "Sat";
"lng_weekday7" = "Sun";
"lng_weekday1_full" = "Monday";
"lng_weekday2_full" = "Tuesday";
"lng_weekday3_full" = "Wednesday";
"lng_weekday4_full" = "Thursday";
"lng_weekday5_full" = "Friday";
"lng_weekday6_full" = "Saturday";
"lng_weekday7_full" = "Sunday";
"lng_month_day" = "{month} {day}";
"lng_month_day_year" = "{month} {day}, {year}";
"lng_month_year" = "{month} {year}";
@@ -104,7 +95,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_status_recently" = "last seen recently";
"lng_status_last_week" = "last seen within a week";
"lng_status_last_month" = "last seen within a month";
"lng_status_invisible" = "invisible";
"lng_status_lastseen_now" = "last seen just now";
"lng_status_lastseen_minutes#one" = "last seen {count} minute ago";
"lng_status_lastseen_minutes#other" = "last seen {count} minutes ago";
@@ -118,7 +108,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_status_connecting" = "connecting...";
"lng_chat_status_unaccessible" = "group is inaccessible";
"lng_chat_status_no_members" = "no members";
"lng_chat_status_members#one" = "{count} member";
"lng_chat_status_members#other" = "{count} members";
"lng_chat_status_online#one" = "{count} online";
@@ -133,7 +122,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_channel_admins_link#one" = "{count} administrator";
"lng_channel_admins_link#other" = "{count} administrators";
"lng_server_error" = "Internal server error.";
"lng_flood_error" = "Too many tries. Please try again later.";
"lng_gif_error" = "An error has occurred while reading GIF animation :(";
"lng_edit_error" = "You cannot edit this message";
@@ -143,7 +131,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_error_pinned_max#one" = "Sorry, you can pin no more than {count} chat to the top.";
"lng_error_pinned_max#other" = "Sorry, you can pin no more than {count} chats to the top.";
"lng_error_public_groups_denied" = "Unfortunately, you were banned from participating in public groups.\n{more_info}";
"lng_error_cant_edit_admin" = "Sorry, you can't edit permissions for this admin.";
"lng_error_cant_add_member" = "Sorry, you can't add the bot to this group. Ask a group admin to do it.";
"lng_error_cant_add_bot" = "Sorry, this bot can't be added to groups.";
"lng_error_cant_add_admin_invite" = "Sorry, you can't add this user as an admin because they are not a member of this group and you are not allowed to invite them.";
@@ -179,14 +166,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_photo_caption" = "Caption";
"lng_photos_comment" = "Comment";
"lng_phone_ph" = "Your phone number";
"lng_phone_title" = "Your Phone";
"lng_phone_desc" = "Please confirm your country code and\nenter your phone number.";
"lng_phone_notreg" = "If you don't have a Telegram account yet,\nplease [b]sign up[/b] with {link_start}Android / iPhone{link_end} or {signup_start}here{signup_end}";
"lng_country_code" = "Country Code";
"lng_bad_country_code" = "Invalid Country Code";
"lng_country_ph" = "Search";
"lng_country_done" = "Done";
"lng_country_none" = "Country not found";
"lng_country_select" = "Select country";
@@ -232,6 +217,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_signin_reset_in_days" = "{days_count} {hours_count} {minutes_count}";
"lng_signin_reset_in_hours" = "{hours_count} {minutes_count}";
"lng_signin_reset_cancelled" = "Your recent attempts to reset this account have been cancelled by its active user. Please try again in 7 days.";
"lng_signin_banned_text" = "This phone number is banned.";
"lng_signin_banned_help" = "Help";
"lng_signup_title" = "Your Info";
"lng_signup_desc" = "Please enter your name and\nupload a photo.";
@@ -276,7 +263,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_bio_about" = "You can add a few lines about yourself. Anyone who opens your profile will see this text.";
"lng_settings_section_info" = "Info";
"lng_settings_phone_number" = "Phone number:";
"lng_settings_username" = "Username:";
"lng_settings_choose_username" = "Choose username";
"lng_settings_empty_bio" = "None";
@@ -316,14 +302,13 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_settings_workmode_window" = "Show taskbar icon";
"lng_settings_auto_start" = "Launch Telegram when system starts";
"lng_settings_start_min" = "Launch minimized";
"lng_settings_add_sendto" = "Place Telegram in «Send to» menu";
"lng_settings_add_sendto" = "Place Telegram in \"Send to\" menu";
"lng_settings_section_scale" = "Interface Scale";
"lng_settings_scale_auto" = "Auto ({cur})";
"lng_settings_section_chat_settings" = "Chat Settings";
"lng_settings_replace_emojis" = "Replace emoji";
"lng_settings_view_emojis" = "View list";
"lng_settings_emoji_list" = "Supported emoji";
"lng_settings_send_enter" = "Send by Enter";
"lng_settings_send_ctrlenter" = "Send by Ctrl+Enter";
"lng_settings_send_cmdenter" = "Send by Cmd+Enter";
@@ -359,7 +344,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_download_finish_failed" = "File download could not be finished.\n\nWould you like to try again?";
"lng_download_path_clearing" = "Clearing...";
"lng_download_path_cleared" = "Cleared!";
"lng_download_path_clear_failed" = "Clear failed :(";
"lng_settings_section_privacy" = "Privacy and Security";
@@ -372,7 +356,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_local_storage_clear" = "Clear all";
"lng_local_storage_clearing" = "Clearing...";
"lng_local_storage_cleared" = "Cleared!";
"lng_local_storage_clear_failed" = "Clear failed :(";
"lng_settings_section_advanced_settings" = "Advanced Settings";
"lng_settings_enable_night_theme" = "Enable night mode";
@@ -460,7 +443,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_settings_reset_sure" = "Are you sure you want to terminate\nall other sessions?";
"lng_settings_reset_one_sure" = "Do you want to terminate this session?";
"lng_settings_reset_button" = "Terminate";
"lng_settings_reset_done" = "Other sessions terminated";
"lng_settings_manage_local_storage" = "Manage local storage";
"lng_settings_ask_question" = "Ask a Question";
"lng_settings_ask_sure" = "Please note that Telegram Support is done by volunteers. We try to respond as quickly as possible, but it may take a while.\n\nPlease take a look at the Telegram FAQ: it has important troubleshooting tips and answers to most questions.";
@@ -472,11 +454,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_settings_need_restart" = "You need to restart for applying some of the new settings. Restart now?";
"lng_settings_restart_now" = "RESTART";
"lng_settings_restart_later" = "LATER";
"lng_sessions_header" = "Current session";
"lng_sessions_other_header" = "Active sessions";
"lng_sessions_no_other" = "No other sessions";
"lng_sessions_other_desc" = "You can log in to Telegram from other mobile, tablet and desktop devices, using the same phone number. All your data will be instantly synchronized.";
"lng_sessions_terminate_all" = "Terminate all other sessions";
@@ -552,17 +532,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_mute_duration_hours#one" = "For {count} hour";
"lng_mute_duration_hours#other" = "For {count} hours";
"lng_mute_box_tip" = "Choose duration of turning off notifications from the following chat";
"lng_mute_box_tip" = "Choose for how long you would like to turn off notifications for the following chat";
"lng_preview_loading" = "Getting Link Info...";
"lng_profile_chat_unaccessible" = "Group is inaccessible";
"lng_profile_about_section" = "About";
"lng_profile_description_section" = "Description";
"lng_profile_settings_section" = "Settings";
"lng_profile_actions_section" = "Actions";
"lng_profile_bot_settings" = "Settings";
"lng_profile_bot_help" = "Help";
"lng_profile_bot_settings" = "Bot Settings";
"lng_profile_bot_help" = "Bot Help";
"lng_profile_invite_link_section" = "Invite link";
"lng_profile_create_public_link" = "Create public link";
"lng_profile_edit_public_link" = "Edit public link";
@@ -573,18 +550,13 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_profile_recent_actions" = "Recent actions";
"lng_profile_common_groups#one" = "{count} group in common";
"lng_profile_common_groups#other" = "{count} groups in common";
"lng_profile_common_groups_section" = "Groups in common";
"lng_profile_participants_section" = "Members";
"lng_profile_info_section" = "Info";
"lng_profile_mobile_number" = "Mobile:";
"lng_profile_username" = "Username:";
"lng_profile_link" = "Link:";
"lng_profile_bio" = "Bio:";
"lng_profile_add_contact" = "Add Contact";
"lng_profile_edit_contact" = "Edit";
"lng_profile_enable_notifications" = "Notifications";
"lng_profile_clear_history" = "Clear history";
"lng_profile_delete_conversation" = "Delete conversation";
"lng_profile_clear_and_exit" = "Delete and exit";
"lng_profile_leave_channel" = "Leave channel";
"lng_profile_delete_channel" = "Delete channel";
@@ -592,28 +564,20 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_profile_delete_group" = "Delete group";
"lng_profile_report" = "Report";
"lng_profile_search_messages" = "Search for messages";
"lng_profile_block_user" = "Block user";
"lng_profile_unblock_user" = "Unblock user";
"lng_profile_block_bot" = "Stop and block bot";
"lng_profile_unblock_bot" = "Unblock bot";
"lng_profile_send_message" = "Send Message";
"lng_profile_share_contact" = "Share Contact";
"lng_profile_invite_to_group" = "Add to Group";
"lng_profile_delete_contact" = "Delete";
"lng_profile_set_group_photo" = "Set Photo";
"lng_profile_add_participant" = "Add Members";
"lng_profile_view_channel" = "View Channel";
"lng_profile_join_channel" = "Join";
"lng_profile_join_channel" = "Join Channel";
"lng_profile_join_group" = "Join Group";
"lng_profile_delete_and_exit" = "Leave";
"lng_profile_kick" = "Remove";
"lng_profile_admin" = "admin";
"lng_profile_edit_permissions" = "Edit";
"lng_profile_sure_kick" = "Remove {user} from the group?";
"lng_profile_sure_kick_channel" = "Remove {user} from the channel?";
"lng_profile_sure_kick_admin" = "Remove {user} from administrators?";
"lng_profile_loading" = "Loading...";
"lng_profile_shared_media" = "Shared media";
"lng_profile_no_media" = "No media in this conversation.";
"lng_profile_photos#one" = "{count} photo";
"lng_profile_photos#other" = "{count} photos";
"lng_profile_photos_header" = "Photos";
@@ -628,6 +592,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_profile_files_header" = "Files";
"lng_profile_audios#one" = "{count} voice message";
"lng_profile_audios#other" = "{count} voice messages";
//"lng_profile_rounds#one" = "{count} video message";
//"lng_profile_rounds#other" = "{count} video messages";
"lng_profile_audios_header" = "Voice messages";
"lng_profile_shared_links#one" = "{count} shared link";
"lng_profile_shared_links#other" = "{count} shared links";
@@ -639,6 +605,76 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_profile_drop_area_subtitle_channel" = "to set it as a channel photo";
"lng_profile_top_bar_share_contact" = "Share";
"lng_profile_info_section" = "Info";
"lng_info_tab_media" = "Media";
"lng_info_mobile_label" = "Mobile";
"lng_info_username_label" = "Username";
"lng_info_bio_label" = "Bio";
"lng_info_link_label" = "Link";
"lng_info_about_label" = "About";
"lng_info_user_title" = "User Info";
"lng_info_bot_title" = "Bot Info";
"lng_info_group_title" = "Group Info";
"lng_info_channel_title" = "Channel Info";
"lng_profile_enable_notifications" = "Notifications";
"lng_profile_send_message" = "Send Message";
"lng_info_add_as_contact" = "Add as contact";
"lng_profile_shared_media" = "Shared media";
"lng_media_type_photos" = "Photos";
"lng_media_type_videos" = "Videos";
"lng_media_type_songs" = "Audio files";
"lng_media_type_files" = "Files";
"lng_media_type_audios" = "Voice messages";
"lng_media_type_links" = "Shared links";
"lng_media_type_rounds" = "Video messages";
"lng_profile_common_groups_section" = "Groups in common";
"lng_profile_share_contact" = "Share Contact";
"lng_info_edit_contact" = "Edit contact";
"lng_info_delete_contact" = "Delete contact";
"lng_info_share_contact" = "Share contact";
"lng_profile_clear_history" = "Clear history";
"lng_profile_delete_conversation" = "Delete conversation";
"lng_profile_block_user" = "Block user";
"lng_profile_unblock_user" = "Unblock user";
"lng_media_selected_photo#one" = "{count} Photo";
"lng_media_selected_photo#other" = "{count} Photos";
"lng_media_selected_video#one" = "{count} Video";
"lng_media_selected_video#other" = "{count} Videos";
"lng_media_selected_song#one" = "{count} Audio file";
"lng_media_selected_song#other" = "{count} Audio files";
"lng_media_selected_file#one" = "{count} File";
"lng_media_selected_file#other" = "{count} Files";
"lng_media_selected_audio#one" = "{count} Voice message";
"lng_media_selected_audio#other" = "{count} Voice messages";
//"lng_media_selected_round#one" = "{count} Video message";
//"lng_media_selected_round#other" = "{count} Video messages";
"lng_media_selected_link#one" = "{count} Shared link";
"lng_media_selected_link#other" = "{count} Shared links";
"lng_media_photo_empty" = "No photos here yet";
"lng_media_video_empty" = "No videos here yet";
"lng_media_song_empty" = "No music files here yet";
"lng_media_file_empty" = "No files here yet";
"lng_media_audio_empty" = "No voice messages here yet";
"lng_media_link_empty" = "No shared links here yet";
"lng_media_song_empty_search" = "No music files found";
"lng_media_file_empty_search" = "No files found";
"lng_media_link_empty_search" = "No shared links found";
"lng_manage_group_title" = "Manage Group";
"lng_manage_channel_title" = "Manage Channel";
"lng_manage_group_info" = "Group Info";
"lng_manage_channel_info" = "Channel Info";
"lng_manage_peer_recent_actions" = "Recent Actions";
"lng_manage_peer_members" = "Members";
"lng_manage_peer_administrators" = "Administrators";
"lng_manage_peer_banned_users" = "Banned users";
"lng_manage_peer_restricted_users" = "Restricted users";
"lng_manage_history_visibility_title" = "Chat history for new members";
"lng_manage_history_visibility_shown" = "Visible";
"lng_manage_history_visibility_shown_about" = "New members will see messages that were sent before they joined.";
"lng_manage_history_visibility_hidden" = "Hidden";
"lng_manage_history_visibility_hidden_about" = "New members won't see earlier messages.";
"lng_report_title" = "Report channel";
"lng_report_group_title" = "Report group";
"lng_report_bot_title" = "Report bot";
@@ -653,12 +689,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_channel_add_members" = "Add members";
"lng_channel_add_banned" = "Ban user";
"lng_channel_add_restricted" = "Restrict user";
"lng_channel_members" = "Members";
"lng_channel_only_last_shown#one" = "Only the last {count} member is shown here";
"lng_channel_only_last_shown#other" = "Only the last {count} members are shown here";
"lng_channel_admins" = "Administrators";
"lng_channel_add_admin" = "Add Administrator";
"lng_channel_admins_too_much" = "Sorry, you have reached the limit of the administrators. Please remove one administrator first.";
"lng_channel_admin_status_creator" = "Creator";
"lng_channel_admin_status_promoted_by" = "Promoted by {user}";
"lng_channel_admin_status_not_admin" = "Not administrator";
@@ -709,8 +741,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_sure_delete_and_exit" = "Are you sure, you want to delete all message history and leave «{group}»?\n\nThis action cannot be undone.";
"lng_sure_leave_channel" = "Are you sure, you want to leave\nthis channel?";
"lng_sure_delete_channel" = "Are you sure, you want to delete this channel? All members will be removed and all messages will be lost.";
"lng_sure_leave_group" = "Are you sure, you want to leave\nthis group? This action cannot be undone.";
"lng_sure_leave_group" = "Are you sure, you want to leave\nthis group?";
"lng_sure_delete_group" = "Are you sure, you want to delete this group? All members will be removed and all messages will be lost.";
"lng_sure_delete_saved_messages" = "Are you sure, you want to delete all your saved messages?\n\nThis action cannot be undone.";
"lng_message_empty" = "Empty Message";
"lng_message_unsupported" = "This message is not supported by your version of Telegram Desktop. Please update to the last version in Settings or install it from {link}";
@@ -730,7 +763,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_action_add_you" = "{from} added you to this channel";
"lng_action_you_joined" = "You joined this channel";
"lng_action_add_you_group" = "{from} added you to this group";
"lng_action_you_joined_group" = "You joined this group";
"lng_action_kick_user" = "{from} removed {user}";
"lng_action_user_left" = "{from} left the group";
"lng_action_user_joined" = "{from} joined the group";
@@ -783,17 +815,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_profile_migrate_reached#other" = "{count} members limit reached";
"lng_profile_migrate_body" = "To get over this limit, you can upgrade your group to a supergroup.";
"lng_profile_migrate_learn_more" = "Learn more »";
"lng_profile_migrate_about" = "If you'd like to go over this limit, you can upgrade your group to a supergroup. In supergroups:";
"lng_profile_migrate_feature1#one" = "— The members limit is {count} user";
"lng_profile_migrate_feature1#other" = "— The members limit is {count} users";
"lng_profile_migrate_feature2" = "— New members see the entire chat history";
"lng_profile_migrate_feature3" = "— Admins delete messages for everyone";
"lng_profile_migrate_feature4" = "— Notifications are muted by default";
"lng_profile_migrate_button" = "Upgrade to supergroup";
"lng_profile_migrate_sure" = "Are you sure you want to upgrade this group to supergroup? This action cannot be undone.";
"lng_profile_convert_button" = "Convert to supergroup";
"lng_profile_convert_title" = "Convert to supergroup";
"lng_profile_convert_about" = "In supergroups:";
"lng_profile_convert_feature1" = "— New members see the full message history";
"lng_profile_convert_feature2" = "— Messages are deleted for all members";
"lng_profile_convert_feature3" = "— Admins can pin important messages";
@@ -812,16 +835,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_channels_too_much_public_revoke" = "Revoke";
"lng_group_invite_bad_link" = "This invite link is broken or has expired.";
"lng_group_invite_want_join" = "Do you want to join the group «{title}»?";
"lng_group_invite_want_join_channel" = "Do you want to join the channel «{title}»?";
"lng_group_invite_join" = "Join";
"lng_group_invite_members#one" = "{count} member, among them:";
"lng_group_invite_members#other" = "{count} members, among them:";
"lng_group_invite_link" = "Invite link:";
"lng_group_invite_create" = "Create an invite link";
"lng_group_invite_about" = "Telegram users will be able to join\nyour group by following this link.";
"lng_group_invite_about_channel" = "Telegram users will be able to join\nyour channel by following this link.";
"lng_group_invite_create_new" = "Revoke invite link";
"lng_group_invite_about_new" = "Your previous link will be deactivated and we'll generate a new invite link for you.";
"lng_group_invite_copied" = "Invite link copied to clipboard.";
@@ -838,12 +859,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_in_reply_to" = "In reply to";
"lng_edited" = "edited";
"lng_edited_date" = "Edited: {date}";
"lng_admin_badge" = "admin";
"lng_cancel_edit_post_sure" = "Cancel editing?";
"lng_cancel_edit_post_yes" = "Yes";
"lng_cancel_edit_post_no" = "No";
"lng_bot_share_location_unavailable" = "Sorry, the location sharing is currently unavailable in Telegram Desktop.";
"lng_bot_inline_geo_unavailable" = "Sorry, this bot requires location sharing.\nIt is not available in Telegram Desktop.";
"lng_bot_share_phone" = "Share Phone Number?";
"lng_bot_share_phone_confirm" = "Share";
@@ -851,14 +872,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_attach_file" = "File";
"lng_attach_photo" = "Photo";
"lng_media_type" = "Media type";
"lng_media_type_photos" = "Photos";
"lng_media_type_videos" = "Videos";
"lng_media_type_songs" = "Audio files";
"lng_media_type_files" = "Files";
"lng_media_type_audios" = "Voice messages";
"lng_media_type_links" = "Shared links";
"lng_media_open_with" = "Open With";
"lng_media_download" = "Download";
"lng_media_cancel" = "Cancel";
@@ -884,7 +897,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_emoji_hide_panel" = "Click here to hide the emoji sidebar";
"lng_recent_stickers" = "Frequently used";
"lng_faved_stickers" = "Favorite stickers";
"lng_faved_stickers_add" = "Add to Favorites";
"lng_faved_stickers_remove" = "Remove from Favorites";
"lng_group_stickers" = "Group stickers";
@@ -911,11 +923,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_stickers_share_pack" = "Share Stickers";
"lng_stickers_not_found" = "Sticker pack not found.";
"lng_stickers_packs_archived" = "Some of your unused stickers have been archived to make room for the sets you've activated.";
"lng_stickers_archived" = "Archived Stickers";
"lng_stickers_copied" = "Sticker pack link copied to clipboard.";
"lng_stickers_default_set" = "Great Minds";
"lng_stickers_you_have" = "Manage and reorder sticker packs";
"lng_stickers_featured" = "Trending Stickers";
"lng_stickers_return" = "Undo";
"lng_stickers_count#one" = "{count} sticker";
"lng_stickers_count#other" = "{count} stickers";
@@ -923,6 +933,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_stickers_group_set" = "Group sticker set";
"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_in_dlg_photo" = "Photo";
"lng_in_dlg_video" = "Video";
@@ -945,16 +956,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_report_spam_ok" = "Report";
"lng_cant_send_to_not_contact" = "Sorry, you can only send messages to\nmutual contacts at the moment.\n{more_info}";
"lng_cant_invite_not_contact" = "Sorry, you can only add mutual contacts\nto groups at the moment.\n{more_info}";
"lng_cant_send_to_not_contact_flood" = "You have contacted too many non-contacts today, please try again tomorrow. You will be able to reply today if this user messages you first.";
"lng_cant_invite_not_contact_flood" = "You can't add this user because you have contacted too many non-contacts today. Please try again tomorrow. You can ask another member to add this user to the group.";
"lng_cant_more_info" = "More info »";
"lng_cant_invite_banned" = "Sorry, only admin can add this user.";
"lng_cant_invite_privacy" = "Sorry, you cannot add this user to groups because of their privacy settings.";
"lng_cant_invite_privacy_channel" = "Sorry, you cannot add this user to channels because of their privacy settings.";
"lng_cant_delete_group#one" = "Sorry, it is currently not possible to manually delete communities that have more than {count} member. Please contact Telegram support if you would like to delete this group.";
"lng_cant_delete_group#other" = "Sorry, it is currently not possible to manually delete communities that have more than {count} members. Please contact Telegram support if you would like to delete this group.";
"lng_cant_delete_channel#one" = "Sorry, it is currently not possible to manually delete communities that have more than {count} member. Please contact Telegram support if you would like to delete this channel.";
"lng_cant_delete_channel#other" = "Sorry, it is currently not possible to manually delete communities that have more than {count} members. Please contact Telegram support if you would like to delete this channel.";
"lng_cant_do_this" = "Sorry, this action is unavailable.";
"lng_send_button" = "Send";
@@ -969,9 +974,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_from_draft" = "Draft";
"lng_bot_description" = "What can this bot do?";
"lng_unblock_button" = "Unblock";
"lng_channel_join" = "Join Channel";
"lng_channel_mute" = "Mute";
"lng_channel_unmute" = "Unmute";
"lng_saved_messages" = "Saved Messages";
"lng_saved_short" = "Save";
"lng_saved_forward_here" = "Forward messages here for quick access";
"lng_dialogs_text_with_from" = "{from_part} {message}";
"lng_dialogs_text_from_wrapped" = "{from}:";
@@ -1023,10 +1030,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_user_action_upload_photo" = "{user} is sending a photo";
"lng_send_action_upload_file" = "sending a file";
"lng_user_action_upload_file" = "{user} is sending a file";
"lng_send_action_geo_location" = "picking a location";
"lng_user_action_geo_location" = "{user} is picking a location";
"lng_send_action_choose_contact" = "choosing a contact";
"lng_user_action_choose_contact" = "{user} is choosing a contact";
"lng_unread_bar#one" = "{count} unread message";
"lng_unread_bar#other" = "{count} unread messages";
@@ -1061,10 +1064,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_context_copy_hashtag" = "Copy Hashtag";
"lng_context_copy_mention" = "Copy Username";
"lng_context_save_image" = "Save Image As...";
"lng_context_forward_image" = "Forward Image";
"lng_context_delete_image" = "Delete Image";
"lng_context_copy_image" = "Copy Image";
"lng_context_close_image" = "Close Image";
"lng_context_cancel_download" = "Cancel Download";
"lng_context_show_in_folder" = "Show in Folder";
"lng_context_show_in_finder" = "Show in Finder";
@@ -1074,9 +1074,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_context_pack_info" = "Pack Info";
"lng_context_pack_add" = "Add Stickers";
"lng_context_save_file" = "Save File As...";
"lng_context_forward_file" = "Forward File";
"lng_context_delete_file" = "Delete File";
"lng_context_close_file" = "Close File";
"lng_context_copy_text" = "Copy Text";
"lng_context_open_gif" = "Open GIF";
"lng_context_save_gif" = "Save GIF";
@@ -1094,15 +1091,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_context_forward_selected" = "Forward Selected";
"lng_context_delete_selected" = "Delete Selected";
"lng_context_clear_selection" = "Clear Selection";
"lng_really_send_image" = "Do you want to send this image?";
"lng_really_send_file" = "Do you want to send this file?";
"lng_really_share_contact" = "Do you want to share this contact?";
"lng_send_images_compress#one" = "Compress image";
"lng_send_images_compress#other" = "Compress images";
"lng_send_image_non_local" = "Could not send a non local file: {name}";
"lng_send_image_empty" = "Could not send an empty file: {name}";
"lng_send_image_too_large" = "Could not send a file, because it is larger than 1500 MB: {name}";
"lng_send_folder" = "Could not send «{name}» because it is a directory :(";
"lng_send_images_selected#one" = "{count} image selected";
"lng_send_images_selected#other" = "{count} images selected";
"lng_send_photos#one" = "Send {count} photo";
@@ -1114,11 +1106,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_forward_choose" = "Choose recipient...";
"lng_forward_cant" = "Sorry, no way to forward here :(";
"lng_forward_confirm" = "Forward to {recipient}?";
"lng_forward_share_contact" = "Share contact to {recipient}?";
"lng_forward_share_cant" = "Sorry, no way to share contact here :(";
"lng_forward_send_file_confirm" = "Send «{name}» to {recipient}?";
"lng_forward_send_files_confirm" = "Send selected files to {recipient}?";
"lng_forward_send_files_cant" = "Sorry, no way to send media here :(";
"lng_forward_send" = "Send";
"lng_forward_messages#one" = "{count} forwarded message";
@@ -1142,7 +1133,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_contact_phone" = "Phone number";
"lng_enter_contact_data" = "New Contact";
"lng_edit_group_title" = "Edit group name";
"lng_edit_contact_title" = "Edit contact name";
"lng_edit_channel_title" = "Edit channel";
"lng_edit_sign_messages" = "Sign messages";
@@ -1159,7 +1149,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_try_other_contact" = "Try other";
"lng_create_group_link" = "Link";
"lng_create_group_invite_link" = "Invite link";
"lng_create_group_photo" = "Set Photo";
"lng_create_group_description" = "Description (optional)";
"lng_drag_images_here" = "Drop images here";
@@ -1173,8 +1162,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_selected_clear" = "Cancel";
"lng_selected_delete" = "Delete";
"lng_selected_forward" = "Forward";
"lng_selected_count#one" = "{count} message";
"lng_selected_count#other" = "{count} messages";
"lng_selected_cancel_sure_this" = "Cancel uploading?";
"lng_selected_upload_stop" = "Stop";
"lng_selected_delete_sure_this" = "Do you want to delete this message?";
@@ -1233,7 +1220,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_new_version_wrap" = "Telegram Desktop was updated to version {version}\n\n{changes}\n\nFull version history is available here:\n{link}";
"lng_new_version_minor" = "— Bug fixes and other minor improvements";
"lng_new_version_text" = "— Improved video messages: radial playback progress, Picture-in-Picture support, duration countdown.\n— Voice and video messages now automatically play one after another.";
"lng_menu_insert_unicode" = "Insert Unicode control character";
@@ -1282,7 +1268,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_call_fingerprint_tooltip" = "If emoji on {user}'s screen are the same, this call is 100% secure";
"lng_call_error_not_available" = "Sorry, {user} doesn't accept calls.";
"lng_call_error_incompatible" = "{user}'s app is using an incompatible protocol. They need to update their app before you can call them.";
"lng_call_error_outdated" = "{user}'s app does not support calls. They need to update their app before you can call them.";
"lng_call_error_audio_io" = "There seems to be a problem with audio playback on your computer. Please make sure that your computer's speakers and microphone are working and try again.";
@@ -1342,7 +1327,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_rights_chat_banned_week#other" = "For {count} weeks";
"lng_rights_chat_banned_custom" = "Custom";
"lng_rights_chat_banned_custom_date" = "Until {date}";
"lng_rights_chat_banned_block" = "Ban and remove from group";
"lng_restricted_send_message" = "The admins of this group restricted you from writing here.";
"lng_restricted_send_media" = "The admins of this group restricted you from posting media content here.";
@@ -1397,6 +1381,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_admin_log_invites_disabled" = "{from} disabled group invites";
"lng_admin_log_signatures_enabled" = "{from} enabled signatures";
"lng_admin_log_signatures_disabled" = "{from} disabled signatures";
"lng_admin_log_history_made_hidden" = "{from} made group history hidden for new members";
"lng_admin_log_history_made_visible" = "{from} made group history visible for new members";
"lng_admin_log_pinned_message" = "{from} pinned message:";
"lng_admin_log_unpinned_message" = "{from} unpinned message";
"lng_admin_log_edited_caption" = "{from} edited caption:";
@@ -1434,15 +1420,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_admin_log_admin_pin_messages" = "Pin messages";
"lng_admin_log_admin_add_admins" = "Add new admins";
// Not used
"lng_topbar_info" = "Info";
"lng_profile_group_info" = "Group info";
"lng_profile_channel_info" = "Channel info";
"lng_channel_add_admins" = "New administrator";
"lng_dlg_search_chat" = "Search in this chat";
"lng_dlg_search_channel" = "Search in this channel";
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose Default Program...";

View File

@@ -0,0 +1,30 @@
import os, sys, requests, re
from os.path import expanduser
filename = ''
for arg in sys.argv:
if re.match(r'.*\.strings$', arg):
filename = expanduser(arg)
result = ''
if not os.path.isfile(filename):
print("File not found.")
sys.exit(1)
with open(filename) as f:
for line in f:
if re.match(r'\s*\/\* new from [a-zA-Z0-9\.]+ \*\/\s*', line):
continue
if re.match(r'\"lng_[a-z_]+\#(zero|two|few|many)\".+', line):
continue
result = result + line
remove = 0
while (len(result) > remove + 1) and (result[len(result) - remove - 1] == '\n') and (result[len(result) - remove - 2] == '\n'):
remove = remove + 1
result = result[:len(result) - remove]
with open('lang.strings', 'w') as out:
out.write(result)
sys.exit()

View File

@@ -0,0 +1,30 @@
set -e
FullExecPath=$PWD
pushd `dirname $0` > /dev/null
FullScriptPath=`pwd`
popd > /dev/null
FileName="$1"
if [ ! -d "$FullScriptPath/../../../../TelegramPrivate" ]; then
echo ""
echo "This script is for building the production version of Telegram Desktop."
echo ""
echo "For building custom versions please visit the build instructions page at:"
echo "https://github.com/telegramdesktop/tdesktop/#build-instructions"
exit
fi
Error () {
cd $FullExecPath
echo "$1"
exit 1
}
if [ ! -f "$FileName" ]; then
Error "File '$FileName' not found."
fi
cd "$FullScriptPath"
python refresh.py $FileName

View File

@@ -159,14 +159,15 @@ inputMediaUploadedPhoto#2f37e231 flags:# file:InputFile caption:string stickers:
inputMediaPhoto#81fa373a flags:# id:InputPhoto caption:string 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:# 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;
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;
inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = 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;
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
inputMediaInvoice#92153685 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string start_param:string = 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;
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
@@ -218,11 +219,11 @@ 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#cb44b1c 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 = 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;
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;
channelFull#17f45fcf flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet = ChatFull;
channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
@@ -235,7 +236,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
message#90dddc11 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 fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string = Message;
message#44f9b43d 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 fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
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;
@@ -245,9 +246,10 @@ messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:str
messageMediaUnsupported#9f84f49e = MessageMedia;
messageMediaDocument#7c4414d3 flags:# document:flags.0?Document caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia;
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia;
messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
messageMediaGame#fdb19008 game:Game = MessageMedia;
messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia;
messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
@@ -267,6 +269,7 @@ messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long pa
messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction;
messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
messageActionScreenshotTaken#4792929b = MessageAction;
messageActionCustomAction#fae69f56 message: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;
@@ -340,6 +343,7 @@ messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesNotModified#74535f21 count:int = messages.Messages;
messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats;
messages.chatsSlice#9cd81144 count:int chats:Vector<Chat> = messages.Chats;
@@ -352,7 +356,6 @@ inputMessagesFilterEmpty#57e2f66c = MessagesFilter;
inputMessagesFilterPhotos#9609a51c = MessagesFilter;
inputMessagesFilterVideo#9fc00e65 = MessagesFilter;
inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter;
inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter;
inputMessagesFilterDocument#9eddf188 = MessagesFilter;
inputMessagesFilterUrl#7ef0dd87 = MessagesFilter;
inputMessagesFilterGif#ffc86587 = MessagesFilter;
@@ -363,6 +366,8 @@ inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFil
inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter;
inputMessagesFilterRoundVideo#b549da53 = MessagesFilter;
inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter;
inputMessagesFilterGeo#e7026d0d = MessagesFilter;
inputMessagesFilterContacts#e062db83 = MessagesFilter;
updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
updateMessageID#4e90bfd6 id:int random_id:long = Update;
@@ -429,6 +434,7 @@ updateLangPack#56022f4d difference:LangPackDifference = Update;
updateFavedStickers#e511996d = Update;
updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector<int> = Update;
updateContactsReset#7084a7be = Update;
updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@@ -455,7 +461,7 @@ upload.fileCdnRedirect#ea52fe5a dc_id:int file_token:bytes encryption_key:bytes
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;
config#8df376a4 flags:# phonecalls_enabled:flags.1?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 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#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;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
@@ -665,6 +671,7 @@ channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter;
channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter;
channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants;
channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants;
channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector<User> = channels.ChannelParticipant;
@@ -680,7 +687,7 @@ messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs;
inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string 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#f4a59de1 flags:# geo_point:InputGeoPoint 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;
@@ -692,18 +699,18 @@ inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:Input
botInlineMessageMediaAuto#a74b15b flags:# caption:string 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#3a8fd8b8 flags:# geo:GeoPoint 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;
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#ccd3563d flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int = messages.BotResults;
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;
messageFwdHeader#fadff4ac flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string = MessageFwdHeader;
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;
auth.codeTypeSms#72a3158c = auth.CodeType;
auth.codeTypeCall#741cd3e3 = auth.CodeType;
@@ -714,7 +721,7 @@ auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType;
auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType;
auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType;
messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer;
messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer;
messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData;
@@ -816,7 +823,7 @@ dataJSON#7d748d04 data:string = DataJSON;
labeledPrice#cb296bf8 label:string amount:long = LabeledPrice;
invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true currency:string prices:Vector<LabeledPrice> = Invoice;
invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector<LabeledPrice> = Invoice;
paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge;
@@ -847,6 +854,8 @@ 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;
account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword;
@@ -903,6 +912,7 @@ channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticip
channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
@@ -917,6 +927,16 @@ 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;
recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl;
recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl;
recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl;
recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl;
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;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -992,7 +1012,7 @@ contacts.resetSaved#879537f1 = Bool;
messages.getMessages#4222fa74 id:Vector<int> = 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#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
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.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;
@@ -1001,7 +1021,7 @@ 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.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = 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;
@@ -1048,8 +1068,8 @@ messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_p
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
messages.editMessage#5d1b8dd flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Updates;
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;
@@ -1080,6 +1100,10 @@ messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int
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.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;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@@ -1108,13 +1132,14 @@ help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
help.getTermsOfService#350170f3 = help.TermsOfService;
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
help.getCdnConfig#52029342 = CdnConfig;
help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
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.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants;
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;
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
@@ -1139,6 +1164,8 @@ channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_right
channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool;
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool;
channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
@@ -1169,4 +1196,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 71
// LAYER 73

View File

@@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="1.1.23.0" />
Version="1.1.29.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,1,23,0
PRODUCTVERSION 1,1,23,0
FILEVERSION 1,1,29,0
PRODUCTVERSION 1,1,29,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.1.23.0"
VALUE "FileVersion", "1.1.29.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2017"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.1.23.0"
VALUE "ProductVersion", "1.1.29.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,23,0
PRODUCTVERSION 1,1,23,0
FILEVERSION 1,1,29,0
PRODUCTVERSION 1,1,29,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.1.23.0"
VALUE "FileVersion", "1.1.29.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2017"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.1.23.0"
VALUE "ProductVersion", "1.1.29.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -30,18 +30,26 @@ bool equal(const wstring &a, const wstring &b) {
void updateError(const WCHAR *msg, DWORD errorCode) {
WCHAR errMsg[2048];
LPWSTR 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), (LPWSTR)&errorText, 0, 0);
if (!errorText) {
errorText = errorTextDefault;
}
LPWSTR errorTextFormatted = nullptr;
auto formatFlags = FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_IGNORE_INSERTS;
FormatMessage(
formatFlags,
NULL,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&errorTextFormatted,
0,
0);
auto errorText = errorTextFormatted
? errorTextFormatted
: L"(Unknown error)";
wsprintf(errMsg, L"%s, error code: %d\nError message: %s", msg, errorCode, errorText);
MessageBox(0, errMsg, L"Update error!", MB_ICONERROR);
if (errorText != errorTextDefault) {
LocalFree(errorText);
}
LocalFree(errorTextFormatted);
}
HANDLE _logFile = 0;
@@ -309,20 +317,20 @@ void updateRegistry() {
WCHAR nameStr[bufSize], dateStr[bufSize], publisherStr[bufSize], icongroupStr[bufSize];
SYSTEMTIME stLocalTime;
GetLocalTime(&stLocalTime);
RegSetValueEx(rkey, L"DisplayVersion", 0, REG_SZ, (BYTE*)versionStr, ((versionLen / 2) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"DisplayVersion", 0, REG_SZ, (const BYTE*)versionStr, ((versionLen / 2) + 1) * sizeof(WCHAR));
wsprintf(nameStr, L"Telegram Desktop version %s", versionStr);
RegSetValueEx(rkey, L"DisplayName", 0, REG_SZ, (BYTE*)nameStr, (wcslen(nameStr) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"DisplayName", 0, REG_SZ, (const BYTE*)nameStr, (wcslen(nameStr) + 1) * sizeof(WCHAR));
wsprintf(publisherStr, L"Telegram Messenger LLP");
RegSetValueEx(rkey, L"Publisher", 0, REG_SZ, (BYTE*)publisherStr, (wcslen(publisherStr) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"Publisher", 0, REG_SZ, (const BYTE*)publisherStr, (wcslen(publisherStr) + 1) * sizeof(WCHAR));
wsprintf(icongroupStr, L"Telegram Desktop");
RegSetValueEx(rkey, L"Inno Setup: Icon Group", 0, REG_SZ, (BYTE*)icongroupStr, (wcslen(icongroupStr) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"Inno Setup: Icon Group", 0, REG_SZ, (const BYTE*)icongroupStr, (wcslen(icongroupStr) + 1) * sizeof(WCHAR));
wsprintf(dateStr, L"%04d%02d%02d", stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay);
RegSetValueEx(rkey, L"InstallDate", 0, REG_SZ, (BYTE*)dateStr, (wcslen(dateStr) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"InstallDate", 0, REG_SZ, (const BYTE*)dateStr, (wcslen(dateStr) + 1) * sizeof(WCHAR));
WCHAR *appURL = L"https://desktop.telegram.org";
RegSetValueEx(rkey, L"HelpLink", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"URLInfoAbout", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"URLUpdateInfo", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR));
const WCHAR *appURL = L"https://desktop.telegram.org";
RegSetValueEx(rkey, L"HelpLink", 0, REG_SZ, (const BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"URLInfoAbout", 0, REG_SZ, (const BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"URLUpdateInfo", 0, REG_SZ, (const BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -20,14 +20,22 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
#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 "chat_helpers/stickers.h"
class AuthSession;
namespace Storage {
enum class SharedMediaType : char;
} // namespace Storage
enum class SparseIdsLoadDirection;
namespace Api {
inline const MTPVector<MTPChat> *getChatsFromMessagesChats(const MTPmessages_Chats &chats) {
@@ -53,10 +61,14 @@ public:
void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer);
void requestPeers(const QList<PeerData*> &peers);
void requestLastParticipants(ChannelData *channel, bool fromStart = true);
void requestBots(ChannelData *channel);
void requestParticipantsCountDelayed(ChannelData *channel);
void requestLastParticipants(not_null<ChannelData*> channel);
void requestBots(not_null<ChannelData*> channel);
void requestAdmins(not_null<ChannelData*> channel);
void requestParticipantsCountDelayed(not_null<ChannelData*> channel);
void requestChannelMembersForAdd(
not_null<ChannelData*> channel,
base::lambda<void(const MTPchannels_ChannelParticipants&)> callback);
void processFullPeer(PeerData *peer, const MTPmessages_ChatFull &result);
void processFullPeer(UserData *user, const MTPUserFull &result);
@@ -89,6 +101,8 @@ public:
void handlePrivacyChange(mtpTypeId keyTypeId, const MTPVector<MTPPrivacyRule> &rules);
int onlineTillFromStatus(const MTPUserStatus &status, int currentOnlineTill);
void clearHistory(not_null<PeerData*> peer);
base::Observable<PeerData*> &fullPeerUpdated() {
return _fullPeerUpdated;
}
@@ -108,6 +122,70 @@ public:
bool adminsEnabled,
base::flat_set<not_null<UserData*>> &&admins);
using SliceType = SparseIdsLoadDirection;
void requestSharedMedia(
not_null<PeerData*> peer,
Storage::SharedMediaType type,
MsgId messageId,
SliceType slice);
void requestSharedMediaCount(
not_null<PeerData*> peer,
Storage::SharedMediaType type);
void requestUserPhotos(
not_null<UserData*> user,
PhotoId afterId);
void stickerSetInstalled(uint64 setId) {
_stickerSetInstalled.fire_copy(setId);
}
auto stickerSetInstalled() const {
return _stickerSetInstalled.events();
}
void readFeaturedSetDelayed(uint64 setId);
void parseChannelParticipants(
not_null<ChannelData*> channel,
const MTPchannels_ChannelParticipants &result,
base::lambda<void(
int availableCount,
const QVector<MTPChannelParticipant> &list)> callbackList,
base::lambda<void()> callbackNotModified = nullptr);
void parseRecentChannelParticipants(
not_null<ChannelData*> channel,
const MTPchannels_ChannelParticipants &result,
base::lambda<void(
int availableCount,
const QVector<MTPChannelParticipant> &list)> callbackList,
base::lambda<void()> callbackNotModified = nullptr);
struct SendOptions {
SendOptions(not_null<History*> history) : history(history) {
}
not_null<History*> history;
MsgId replyTo = 0;
WebPageId webPageId = 0;
bool clearDraft = false;
bool generateLocal = true;
};
rpl::producer<SendOptions> sendActions() const {
return _sendActions.events();
}
void sendAction(const SendOptions &options);
void forwardMessages(
HistoryItemsList &&items,
const SendOptions &options,
base::lambda_once<void()> &&successCallback = nullptr);
void shareContact(
const QString &phone,
const QString &firstName,
const QString &lastName,
const SendOptions &options);
void shareContact(not_null<UserData*> user, const SendOptions &options);
void readServerHistory(not_null<History*> history);
void readServerHistoryForce(not_null<History*> history);
~ApiWrap();
private:
@@ -117,6 +195,7 @@ private:
Callbacks callbacks;
};
using MessageDataRequests = QMap<MsgId, MessageDataRequest>;
using SharedMediaType = Storage::SharedMediaType;
void requestAppChangelogs();
void addLocalChangelogs(int oldAppVersion);
@@ -127,13 +206,27 @@ private:
void resolveMessageDatas();
void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId requestId);
void finalizeMessageDataRequest(
ChannelData *channel,
mtpRequestId requestId);
QVector<MTPint> collectMessageIds(const MessageDataRequests &requests);
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req);
void gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestId req);
void lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelParticipants &result, mtpRequestId req);
void applyLastParticipantsList(
not_null<ChannelData*> channel,
int availableCount,
const QVector<MTPChannelParticipant> &list);
void applyBotsList(
not_null<ChannelData*> channel,
int availableCount,
const QVector<MTPChannelParticipant> &list);
void applyAdminsList(
not_null<ChannelData*> channel,
int availableCount,
const QVector<MTPChannelParticipant> &list);
void resolveWebPages();
void gotWebPages(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req);
void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result);
@@ -148,10 +241,48 @@ private:
void requestFavedStickers(TimeId now);
void requestFeaturedStickers(TimeId now);
void requestSavedGifs(TimeId now);
void readFeaturedSets();
void cancelEditChatAdmins(not_null<ChatData*> chat);
void saveChatAdmins(not_null<ChatData*> chat);
void sendSaveChatAdminsRequests(not_null<ChatData*> chat);
void refreshChannelAdmins(
not_null<ChannelData*> channel,
const QVector<MTPChannelParticipant> &participants);
template <typename Callback>
void requestMessageAfterDate(
not_null<PeerData*> peer,
const QDate &date,
Callback &&callback);
void sharedMediaDone(
not_null<PeerData*> peer,
SharedMediaType type,
MsgId messageId,
SliceType slice,
const MTPmessages_Messages &result);
void userPhotosDone(
not_null<UserData*> user,
PhotoId photoId,
const MTPphotos_Photos &result);
void sendSharedContact(
const QString &phone,
const QString &firstName,
const QString &lastName,
UserId userId,
const SendOptions &options);
void sendReadRequest(not_null<PeerData*> peer, MsgId upTo);
int applyAffectedHistory(
not_null<PeerData*> peer,
const MTPmessages_AffectedHistory &result);
void applyAffectedMessages(const MTPmessages_AffectedMessages &result);
void applyAffectedMessages(
not_null<PeerData*> peer,
const MTPmessages_AffectedMessages &result);
not_null<AuthSession*> _session;
mtpRequestId _changelogSubscription = 0;
@@ -166,8 +297,13 @@ private:
PeerRequests _participantsRequests;
PeerRequests _botsRequests;
PeerRequests _adminsRequests;
base::DelayedCallTimer _participantsCountRequestTimer;
ChannelData *_channelMembersForAdd = nullptr;
mtpRequestId _channelMembersForAddRequestId = 0;
base::lambda<void(const MTPchannels_ChannelParticipants&)> _channelMembersForAddCallback;
typedef QPair<PeerData*, UserData*> KickRequest;
typedef QMap<KickRequest, mtpRequestId> KickRequests;
KickRequests _kickRequests;
@@ -188,7 +324,7 @@ private:
QMap<History*, mtpRequestId> _draftsSaveRequestIds;
base::Timer _draftsSaveTimer;
OrderedSet<mtpRequestId> _stickerSetDisenableRequests;
base::flat_set<mtpRequestId> _stickerSetDisenableRequests;
Stickers::Order _stickersOrder;
mtpRequestId _stickersReorderRequestId = 0;
mtpRequestId _stickersClearRecentRequestId = 0;
@@ -199,16 +335,49 @@ private:
mtpRequestId _featuredStickersUpdateRequest = 0;
mtpRequestId _savedGifsUpdateRequest = 0;
base::Timer _featuredSetsReadTimer;
base::flat_set<uint64> _featuredSetsRead;
QMap<mtpTypeId, mtpRequestId> _privacySaveRequests;
mtpRequestId _contactsStatusesRequestId = 0;
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;
base::flat_map<not_null<ChatData*>, mtpRequestId> _chatAdminsEnabledRequests;
base::flat_map<not_null<ChatData*>, base::flat_set<not_null<UserData*>>> _chatAdminsToSave;
base::flat_map<not_null<ChatData*>, base::flat_set<mtpRequestId>> _chatAdminsSaveRequests;
base::flat_map<
not_null<ChatData*>,
mtpRequestId> _chatAdminsEnabledRequests;
base::flat_map<
not_null<ChatData*>,
base::flat_set<not_null<UserData*>>> _chatAdminsToSave;
base::flat_map<
not_null<ChatData*>,
base::flat_set<mtpRequestId>> _chatAdminsSaveRequests;
base::flat_map<std::tuple<
not_null<PeerData*>,
SharedMediaType,
MsgId,
SliceType>, mtpRequestId> _sharedMediaRequests;
base::flat_map<not_null<UserData*>, mtpRequestId> _userPhotosRequests;
rpl::event_stream<SendOptions> _sendActions;
struct ReadRequest {
ReadRequest(mtpRequestId requestId, MsgId upTo)
: requestId(requestId)
, upTo(upTo) {
}
mtpRequestId requestId = 0;
MsgId upTo = 0;
};
base::flat_map<not_null<PeerData*>, ReadRequest> _readRequests;
base::flat_map<not_null<PeerData*>, MsgId> _readRequestsPending;
base::Observable<PeerData*> _fullPeerUpdated;
rpl::event_stream<uint64> _stickerSetInstalled;
};

View File

@@ -46,6 +46,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "numbers.h"
#include "observer_peer.h"
#include "auth_session.h"
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
#include "window/themes/window_theme.h"
#include "window/notifications_manager.h"
#include "platform/platform_notifications_manager.h"
@@ -58,7 +60,7 @@ namespace {
using PeersData = QHash<PeerId, PeerData*>;
PeersData peersData;
using MutedPeers = QMap<PeerData*, bool>;
using MutedPeers = QMap<not_null<PeerData*>, bool>;
MutedPeers mutedPeers;
PhotosData photosData;
@@ -193,9 +195,6 @@ namespace {
Window::Theme::Background()->reset();
cSetOtherOnline(0);
globalNotifyAllPtr = UnknownNotifySettings;
globalNotifyUsersPtr = UnknownNotifySettings;
globalNotifyChatsPtr = UnknownNotifySettings;
clearStorageImages();
if (auto w = wnd()) {
w->updateConnectingStatus();
@@ -206,7 +205,11 @@ namespace {
void logOut() {
if (auto mtproto = Messenger::Instance().mtp()) {
mtproto->logout(rpcDone(&loggedOut), rpcFail(&loggedOut));
mtproto->logout(rpcDone([] {
return loggedOut();
}), rpcFail([] {
return loggedOut();
}));
} else {
// We log out because we've forgotten passcode.
// So we just start mtproto from scratch.
@@ -254,11 +257,11 @@ namespace {
int32 onlineWillChangeIn(TimeId online, TimeId now) {
if (online <= 0) {
if (-online > now) return -online - now;
if (-online > now) return std::max(-online - now, 86400);
return 86400;
}
if (online > now) {
return online - now;
return std::max(online - now, 86400);
}
int32 minutes = (now - online) / 60;
if (minutes < 60) {
@@ -269,7 +272,7 @@ namespace {
return (hours + 1) * 3600 - (now - online);
}
QDateTime dNow(date(now)), dTomorrow(dNow.date().addDays(1));
return dNow.secsTo(dTomorrow);
return std::max(dNow.secsTo(dTomorrow), 86400LL);
}
QString onlineText(UserData *user, TimeId now, bool precise) {
@@ -286,8 +289,8 @@ namespace {
QString onlineText(TimeId online, TimeId now, bool precise) {
if (online <= 0) {
switch (online) {
case 0: return lang(lng_status_offline);
case -1: return lang(lng_status_invisible);
case 0:
case -1: return lang(lng_status_offline);
case -2: return lang(lng_status_recently);
case -3: return lang(lng_status_last_week);
case -4: return lang(lng_status_last_month);
@@ -392,8 +395,8 @@ namespace {
data->inputUser = MTP_inputUser(d.vid, MTP_long(0));
data->setName(lang(lng_deleted), QString(), QString(), QString());
data->setPhoto(MTP_userProfilePhotoEmpty());
data->setIsInaccessible();
data->flags = 0;
//data->setFlags(MTPDuser_ClientFlag::f_inaccessible | 0);
data->setFlags(MTPDuser::Flag::f_deleted);
data->setBotInfoVersion(-1);
status = &emptyStatus;
data->contact = -1;
@@ -409,14 +412,19 @@ namespace {
data = App::user(peer);
auto canShareThisContact = data->canShareThisContactFast();
wasContact = data->isContact();
if (!minimal) {
data->flags = d.vflags.v;
if (minimal) {
auto mask = 0
//| MTPDuser_ClientFlag::f_inaccessible
| MTPDuser::Flag::f_deleted;
data->setFlags((data->flags() & ~mask) | (d.vflags.v & mask));
} else {
data->setFlags(d.vflags.v);
if (d.is_self()) {
data->input = MTP_inputPeerSelf();
data->inputUser = MTP_inputUserSelf();
} else if (!d.has_access_hash()) {
data->input = MTP_inputPeerUser(d.vid, MTP_long(data->isInaccessible() ? 0 : data->access));
data->inputUser = MTP_inputUser(d.vid, MTP_long(data->isInaccessible() ? 0 : data->access));
data->input = MTP_inputPeerUser(d.vid, MTP_long(data->accessHash()));
data->inputUser = MTP_inputUser(d.vid, MTP_long(data->accessHash()));
} else {
data->input = MTP_inputPeerUser(d.vid, d.vaccess_hash);
data->inputUser = MTP_inputUser(d.vid, d.vaccess_hash);
@@ -434,7 +442,6 @@ namespace {
}
data->setName(lang(lng_deleted), QString(), QString(), QString());
data->setPhoto(MTP_userProfilePhotoEmpty());
data->setIsInaccessible();
status = &emptyStatus;
} else {
// apply first_name and last_name from minimal user only if we don't have
@@ -473,7 +480,9 @@ namespace {
} else {
data->setPhoto(MTP_userProfilePhotoEmpty());
}
if (d.has_access_hash()) data->access = d.vaccess_hash.v;
if (d.has_access_hash()) {
data->setAccessHash(d.vaccess_hash.v);
}
status = d.has_status() ? &d.vstatus : &emptyStatus;
}
if (!minimal) {
@@ -577,12 +586,9 @@ namespace {
cdata->date = d.vdate.v;
if (d.has_migrated_to() && d.vmigrated_to.type() == mtpc_inputChannel) {
const auto &c(d.vmigrated_to.c_inputChannel());
ChannelData *channel = App::channel(peerFromChannel(c.vchannel_id));
if (!channel->mgInfo) {
channel->flags |= MTPDchannel::Flag::f_megagroup;
channel->flagsUpdated();
}
auto &c = d.vmigrated_to.c_inputChannel();
auto channel = App::channel(peerFromChannel(c.vchannel_id));
channel->addFlags(MTPDchannel::Flag::f_megagroup);
if (!channel->access) {
channel->input = MTP_inputPeerChannel(c.vchannel_id, c.vaccess_hash);
channel->inputChannel = d.vmigrated_to;
@@ -594,8 +600,8 @@ namespace {
}
if (updatedFrom) {
channel->mgInfo->migrateFromPtr = cdata;
if (History *h = App::historyLoaded(cdata->id)) {
if (History *hto = App::historyLoaded(channel->id)) {
if (auto h = App::historyLoaded(cdata->id)) {
if (auto hto = App::historyLoaded(channel->id)) {
if (!h->isEmpty()) {
h->clear(true);
}
@@ -613,13 +619,12 @@ namespace {
}
}
if (!(cdata->flags & MTPDchat::Flag::f_admins_enabled) && (d.vflags.v & MTPDchat::Flag::f_admins_enabled)) {
if (!(cdata->flags() & MTPDchat::Flag::f_admins_enabled) && (d.vflags.v & MTPDchat::Flag::f_admins_enabled)) {
cdata->invalidateParticipants();
}
cdata->flags = d.vflags.v;
cdata->setFlags(d.vflags.v);
cdata->count = d.vparticipants_count.v;
cdata->setIsForbidden(false);
if (canEdit != cdata->canEdit()) {
update.flags |= UpdateFlag::ChatCanEdit;
}
@@ -637,8 +642,7 @@ namespace {
cdata->date = 0;
cdata->count = -1;
cdata->invalidateParticipants();
cdata->flags = 0;
cdata->setIsForbidden(true);
cdata->setFlags(MTPDchat_ClientFlag::f_forbidden | 0);
if (canEdit != cdata->canEdit()) {
update.flags |= UpdateFlag::ChatCanEdit;
}
@@ -665,8 +669,13 @@ namespace {
auto canAddMembers = cdata->canAddMembers();
if (minimal) {
auto mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy;
cdata->flags = (cdata->flags & ~mask) | (d.vflags.v & mask);
auto mask = 0
| MTPDchannel::Flag::f_broadcast
| MTPDchannel::Flag::f_verified
| MTPDchannel::Flag::f_megagroup
| MTPDchannel::Flag::f_democracy
| MTPDchannel_ClientFlag::f_forbidden;
cdata->setFlags((cdata->flags() & ~mask) | (d.vflags.v & mask));
} else {
if (d.has_admin_rights()) {
cdata->setAdminRights(d.vadmin_rights);
@@ -675,7 +684,7 @@ namespace {
}
if (d.has_banned_rights()) {
cdata->setRestrictedRights(d.vbanned_rights);
} else if (cdata->hasRestrictedRights()) {
} else if (cdata->hasRestrictions()) {
cdata->setRestrictedRights(MTP_channelBannedRights(MTP_flags(0), MTP_int(0)));
}
cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
@@ -689,14 +698,12 @@ namespace {
} else {
cdata->setRestrictionReason(QString());
}
cdata->flags = d.vflags.v;
cdata->setFlags(d.vflags.v);
}
cdata->flagsUpdated();
QString uname = d.has_username() ? TextUtilities::SingleLine(qs(d.vusername)) : QString();
cdata->setName(qs(d.vtitle), uname);
cdata->setIsForbidden(false);
cdata->setPhoto(d.vphoto);
if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn;
@@ -720,13 +727,12 @@ namespace {
cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
auto mask = mtpCastFlags(MTPDchannelForbidden::Flag::f_broadcast | MTPDchannelForbidden::Flag::f_megagroup);
cdata->flags = (cdata->flags & ~mask) | (mtpCastFlags(d.vflags) & mask);
cdata->flagsUpdated();
cdata->setFlags((cdata->flags() & ~mask) | (mtpCastFlags(d.vflags) & mask) | MTPDchannel_ClientFlag::f_forbidden);
if (cdata->hasAdminRights()) {
cdata->setAdminRights(MTP_channelAdminRights(MTP_flags(0)));
}
if (cdata->hasRestrictedRights()) {
if (cdata->hasRestrictions()) {
cdata->setRestrictedRights(MTP_channelBannedRights(MTP_flags(0), MTP_int(0)));
}
@@ -736,7 +742,6 @@ namespace {
cdata->setPhoto(MTP_chatPhotoEmpty());
cdata->date = 0;
cdata->setMembersCount(0);
cdata->setIsForbidden(true);
if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn;
if (canViewAdmins != cdata->canViewAdmins()
@@ -790,10 +795,12 @@ namespace {
chat->version = d.vversion.v;
auto &v = d.vparticipants.v;
chat->count = v.size();
int32 pversion = chat->participants.isEmpty() ? 1 : (chat->participants.begin().value() + 1);
int32 pversion = chat->participants.empty()
? 1
: (chat->participants.begin()->second + 1);
chat->invitedByMe.clear();
chat->admins.clear();
chat->flags &= ~MTPDchat::Flag::f_admin;
chat->removeFlags(MTPDchat::Flag::f_admin);
for (auto i = v.cbegin(), e = v.cend(); i != e; ++i) {
int32 uid = 0, inviter = 0;
switch (i->type()) {
@@ -824,7 +831,7 @@ namespace {
if (i->type() == mtpc_chatParticipantAdmin) {
chat->admins.insert(user);
if (user->isSelf()) {
chat->flags |= MTPDchat::Flag::f_admin;
chat->addFlags(MTPDchat::Flag::f_admin);
}
}
} else {
@@ -832,21 +839,22 @@ namespace {
break;
}
}
if (!chat->participants.isEmpty()) {
History *h = App::historyLoaded(chat->id);
if (!chat->participants.empty()) {
auto h = App::historyLoaded(chat->id);
bool found = !h || !h->lastKeyboardFrom;
int32 botStatus = -1;
auto botStatus = -1;
for (auto i = chat->participants.begin(), e = chat->participants.end(); i != e;) {
if (i.value() < pversion) {
auto [user, version] = *i;
if (version < pversion) {
i = chat->participants.erase(i);
} else {
if (i.key()->botInfo) {
botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1;
if (requestBotInfos && !i.key()->botInfo->inited) {
Auth().api().requestFullPeer(i.key());
if (user->botInfo) {
botStatus = 2;// (botStatus > 0/* || !user->botInfo->readsAllHistory*/) ? 2 : 1;
if (requestBotInfos && !user->botInfo->inited) {
Auth().api().requestFullPeer(user);
}
}
if (!found && i.key()->id == h->lastKeyboardFrom) {
if (!found && user->id == h->lastKeyboardFrom) {
found = true;
}
++i;
@@ -876,11 +884,11 @@ namespace {
chat->version = d.vversion.v;
UserData *user = App::userLoaded(d.vuser_id.v);
if (user) {
if (chat->participants.isEmpty() && chat->count) {
if (chat->participants.empty() && chat->count) {
chat->count++;
chat->botStatus = 0;
} else if (chat->participants.find(user) == chat->participants.end()) {
chat->participants[user] = (chat->participants.isEmpty() ? 1 : chat->participants.begin().value());
chat->participants[user] = (chat->participants.empty() ? 1 : chat->participants.begin()->second);
if (d.vinviter_id.v == Auth().userId()) {
chat->invitedByMe.insert(user);
} else {
@@ -913,7 +921,7 @@ namespace {
auto canEdit = chat->canEdit();
UserData *user = App::userLoaded(d.vuser_id.v);
if (user) {
if (chat->participants.isEmpty()) {
if (chat->participants.empty()) {
if (chat->count > 0) {
chat->count--;
}
@@ -925,7 +933,7 @@ namespace {
chat->invitedByMe.remove(user);
chat->admins.remove(user);
if (user->isSelf()) {
chat->flags &= ~MTPDchat::Flag::f_admin;
chat->removeFlags(MTPDchat::Flag::f_admin);
}
History *h = App::historyLoaded(chat->id);
@@ -935,9 +943,9 @@ namespace {
}
if (chat->botStatus > 0 && user->botInfo) {
int32 botStatus = -1;
for (auto j = chat->participants.cbegin(), e = chat->participants.cend(); j != e; ++j) {
if (j.key()->botInfo) {
if (true || botStatus > 0/* || !j.key()->botInfo->readsAllHistory*/) {
for (auto [participant, v] : chat->participants) {
if (participant->botInfo) {
if (true || botStatus > 0/* || !participant->botInfo->readsAllHistory*/) {
botStatus = 2;
break;
}
@@ -959,23 +967,28 @@ namespace {
}
void feedChatAdmins(const MTPDupdateChatAdmins &d) {
ChatData *chat = App::chat(d.vchat_id.v);
auto chat = App::chat(d.vchat_id.v);
if (chat->version <= d.vversion.v) {
bool badVersion = (chat->version + 1 < d.vversion.v);
if (badVersion) {
auto wasCanEdit = chat->canEdit();
auto badVersion = (chat->version + 1 < d.vversion.v);
chat->version = d.vversion.v;
if (mtpIsTrue(d.venabled)) {
chat->addFlags(MTPDchat::Flag::f_admins_enabled);
} else {
chat->removeFlags(MTPDchat::Flag::f_admins_enabled);
}
if (badVersion || mtpIsTrue(d.venabled)) {
chat->invalidateParticipants();
Auth().api().requestPeer(chat);
}
chat->version = d.vversion.v;
if (mtpIsTrue(d.venabled)) {
if (!badVersion) {
chat->invalidateParticipants();
}
chat->flags |= MTPDchat::Flag::f_admins_enabled;
} else {
chat->flags &= ~MTPDchat::Flag::f_admins_enabled;
if (wasCanEdit != chat->canEdit()) {
Notify::peerUpdatedDelayed(
chat,
Notify::PeerUpdate::Flag::ChatCanEdit);
}
Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged);
Notify::peerUpdatedDelayed(
chat,
Notify::PeerUpdate::Flag::AdminsChanged);
}
}
@@ -992,7 +1005,7 @@ namespace {
if (user) {
if (mtpIsTrue(d.vis_admin)) {
if (user->isSelf()) {
chat->flags |= MTPDchat::Flag::f_admin;
chat->addFlags(MTPDchat::Flag::f_admin);
}
if (chat->noParticipantInfo()) {
Auth().api().requestFullPeer(chat);
@@ -1001,7 +1014,7 @@ namespace {
}
} else {
if (user->isSelf()) {
chat->flags &= ~MTPDchat::Flag::f_admin;
chat->removeFlags(MTPDchat::Flag::f_admin);
}
chat->admins.remove(user);
}
@@ -1027,7 +1040,13 @@ namespace {
existing->updateMedia(m.has_media() ? (&m.vmedia) : nullptr);
existing->updateReplyMarkup(m.has_reply_markup() ? (&m.vreply_markup) : nullptr);
existing->setViewsCount(m.has_views() ? m.vviews.v : -1);
existing->addToOverview(AddToOverviewNew);
existing->addToUnreadMentions(AddToUnreadMentionsMethod::New);
if (auto sharedMediaTypes = existing->sharedMediaTypes()) {
Auth().storage().add(Storage::SharedMediaAddNew(
peerId,
sharedMediaTypes,
existing->id));
}
if (!existing->detached()) {
App::checkSavedGif(existing);
@@ -1039,27 +1058,26 @@ namespace {
return false;
}
template <typename TMTPDclass>
void updateEditedMessage(const TMTPDclass &m) {
auto peerId = peerFromMTP(m.vto_id);
if (m.has_from_id() && peerId == Auth().userPeerId()) {
peerId = peerFromUser(m.vfrom_id);
}
if (auto existing = App::histItemById(peerToChannel(peerId), m.vid.v)) {
existing->applyEdition(m);
}
}
void updateEditedMessage(const MTPMessage &m) {
auto apply = [](const auto &data) {
auto peerId = peerFromMTP(data.vto_id);
if (data.has_from_id() && peerId == Auth().userPeerId()) {
peerId = peerFromUser(data.vfrom_id);
}
if (auto existing = App::histItemById(peerToChannel(peerId), data.vid.v)) {
existing->applyEdition(data);
}
};
if (m.type() == mtpc_message) { // apply message edit
App::updateEditedMessage(m.c_message());
apply(m.c_message());
} else if (m.type() == mtpc_messageService) {
App::updateEditedMessage(m.c_messageService());
apply(m.c_messageService());
}
}
void addSavedGif(DocumentData *doc) {
SavedGifs &saved(cRefSavedGifs());
auto &saved = Auth().data().savedGifsRef();
int32 index = saved.indexOf(doc);
if (index) {
if (index > 0) saved.remove(index);
@@ -1067,8 +1085,8 @@ namespace {
if (saved.size() > Global::SavedGifsLimit()) saved.pop_back();
Local::writeSavedGifs();
Auth().data().savedGifsUpdated().notify();
cSetLastSavedGifsUpdate(0);
Auth().data().markSavedGifsUpdated();
Auth().data().setLastSavedGifsUpdate(0);
Auth().api().updateStickers();
}
}
@@ -1140,28 +1158,6 @@ namespace {
return ImagePtr();
}
StorageImageLocation imageLocation(int32 w, int32 h, const MTPFileLocation &loc) {
if (loc.type() == mtpc_fileLocation) {
const auto &l(loc.c_fileLocation());
return StorageImageLocation(w, h, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v);
}
return StorageImageLocation(w, h, 0, 0, 0, 0);
}
StorageImageLocation imageLocation(const MTPPhotoSize &size) {
switch (size.type()) {
case mtpc_photoSize: {
const auto &d(size.c_photoSize());
return imageLocation(d.vw.v, d.vh.v, d.vlocation);
} break;
case mtpc_photoCachedSize: {
const auto &d(size.c_photoCachedSize());
return imageLocation(d.vw.v, d.vh.v, d.vlocation);
} break;
}
return StorageImageLocation();
}
void feedInboxRead(const PeerId &peer, MsgId upTo) {
if (auto history = App::historyLoaded(peer)) {
history->inboxRead(upTo);
@@ -1399,7 +1395,18 @@ namespace {
}
DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert) {
return App::documentSet(document.vid.v, convert, document.vaccess_hash.v, document.vversion.v, document.vdate.v, document.vattributes.v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v, App::imageLocation(document.vthumb));
return App::documentSet(
document.vid.v,
convert,
document.vaccess_hash.v,
document.vversion.v,
document.vdate.v,
document.vattributes.v,
qs(document.vmime_type),
App::image(document.vthumb),
document.vdc_id.v,
document.vsize.v,
StorageImageLocation::FromMTP(document.vthumb));
}
WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert) {
@@ -1596,7 +1603,7 @@ namespace {
versionChanged = convert->setRemoteVersion(version);
convert->setRemoteLocation(dc, access);
convert->date = date;
convert->mime = mime;
convert->setMimeString(mime);
if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height() || versionChanged)) {
updateImage(convert->thumb, thumb);
}
@@ -1616,7 +1623,7 @@ namespace {
}
}
if (cSavedGifs().indexOf(convert) >= 0) { // id changed
if (Auth().data().savedGifs().indexOf(convert) >= 0) { // id changed
Local::writeSavedGifs();
}
}
@@ -1628,7 +1635,7 @@ namespace {
} else {
result = DocumentData::create(document, dc, access, version, attributes);
result->date = date;
result->mime = mime;
result->setMimeString(mime);
result->thumb = thumb;
result->size = size;
result->recountIsImage();
@@ -1646,7 +1653,7 @@ namespace {
result->setRemoteLocation(dc, access);
}
result->date = date;
result->mime = mime;
result->setMimeString(mime);
if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height() || versionChanged)) {
result->thumb = thumb;
}
@@ -1662,8 +1669,8 @@ namespace {
}
if (versionChanged) {
if (result->sticker() && result->sticker()->set.type() == mtpc_inputStickerSetID) {
auto it = Global::StickerSets().constFind(result->sticker()->set.c_inputStickerSetID().vid.v);
if (it != Global::StickerSets().cend()) {
auto it = Auth().data().stickerSets().constFind(result->sticker()->set.c_inputStickerSetID().vid.v);
if (it != Auth().data().stickerSets().cend()) {
if (it->id == Stickers::CloudRecentSetId) {
Local::writeRecentStickers();
} else if (it->id == Stickers::FavedSetId) {
@@ -1938,8 +1945,10 @@ namespace {
}
}
Auth().notifications().clearFromItem(item);
if (Global::started() && !App::quitting()) {
Global::RefItemRemoved().notify(item, true);
if (Global::started()
&& !App::quitting()
&& AuthSession::Exists()) {
Auth().data().markItemRemoved(item);
}
}
@@ -2013,19 +2022,6 @@ namespace {
Auth().api().clearWebPageRequests();
}
cSetRecentStickers(RecentStickerPack());
Global::SetStickerSets(Stickers::Sets());
Global::SetStickerSetsOrder(Stickers::Order());
Global::SetLastStickersUpdate(0);
Global::SetLastRecentStickersUpdate(0);
Global::SetFeaturedStickerSetsOrder(Stickers::Order());
if (Global::FeaturedStickerSetsUnreadCount() != 0) {
Global::SetFeaturedStickerSetsUnreadCount(0);
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
}
Global::SetLastFeaturedStickersUpdate(0);
Global::SetArchivedStickerSetsOrder(Stickers::Order());
cSetSavedGifs(SavedGifs());
cSetLastSavedGifsUpdate(0);
cSetReportSpamStatuses(ReportSpamStatuses());
cSetAutoDownloadPhoto(0);
cSetAutoDownloadAudio(0);
@@ -2587,28 +2583,32 @@ namespace {
return QString();
}
void regMuted(PeerData *peer, int32 changeIn) {
void regMuted(not_null<PeerData*> peer, TimeMs changeIn) {
::mutedPeers.insert(peer, true);
if (App::main()) App::main()->updateMutedIn(changeIn);
App::main()->updateMutedIn(changeIn);
}
void unregMuted(PeerData *peer) {
void unregMuted(not_null<PeerData*> peer) {
::mutedPeers.remove(peer);
}
void updateMuted() {
int32 changeInMin = 0;
for (MutedPeers::iterator i = ::mutedPeers.begin(); i != ::mutedPeers.end();) {
int32 changeIn = 0;
History *h = App::history(i.key()->id);
if (isNotifyMuted(i.key()->notify, &changeIn)) {
h->setMute(true);
if (changeIn && (!changeInMin || changeIn < changeInMin)) {
changeInMin = changeIn;
auto changeInMin = TimeMs(0);
for (auto i = ::mutedPeers.begin(); i != ::mutedPeers.end();) {
const auto history = App::historyLoaded(i.key()->id);
const auto muteFinishesIn = i.key()->notifyMuteFinishesIn();
if (muteFinishesIn > 0) {
if (history) {
history->changeMute(true);
}
if (!changeInMin || muteFinishesIn < changeInMin) {
changeInMin = muteFinishesIn;
}
++i;
} else {
h->setMute(false);
if (history) {
history->changeMute(false);
}
i = ::mutedPeers.erase(i);
}
}

View File

@@ -82,8 +82,6 @@ namespace App {
void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink);
ImagePtr image(const MTPPhotoSize &size);
StorageImageLocation imageLocation(int32 w, int32 h, const MTPFileLocation &loc);
StorageImageLocation imageLocation(const MTPPhotoSize &size);
PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs);
PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = nullptr);
@@ -262,8 +260,8 @@ namespace App {
void stopRoundVideoPlayback();
void stopGifItems();
void regMuted(PeerData *peer, int32 changeIn);
void unregMuted(PeerData *peer);
void regMuted(not_null<PeerData*> peer, TimeMs changeIn);
void unregMuted(not_null<PeerData*> peer);
void updateMuted();
void setProxySettings(QNetworkAccessManager &manager);

View File

@@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "storage/file_download.h"
#include "storage/file_upload.h"
#include "storage/localstorage.h"
#include "storage/storage_facade.h"
#include "storage/serialize_common.h"
#include "window/notifications_manager.h"
#include "platform/platform_specific.h"
@@ -45,7 +46,7 @@ AuthSessionData::Variables::Variables()
}
QByteArray AuthSessionData::serialize() const {
auto size = sizeof(qint32) * 8;
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());
}
@@ -70,6 +71,14 @@ QByteArray AuthSessionData::serialize() const {
for (auto peerId : _variables.groupStickersSectionHidden) {
stream << quint64(peerId);
}
stream << qint32(_variables.thirdSectionInfoEnabled ? 1 : 0);
stream << qint32(_variables.smallDialogsList ? 1 : 0);
stream << qint32(snap(
qRound(_variables.dialogsWidthRatio.current() * 1000000),
0,
1000000));
stream << qint32(_variables.thirdColumnWidth.current());
stream << qint32(_variables.thirdSectionExtendedBy);
}
return result;
}
@@ -88,7 +97,12 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) {
qint32 floatPlayerColumn = static_cast<qint32>(Window::Column::Second);
qint32 floatPlayerCorner = static_cast<qint32>(RectPart::TopRight);
QMap<QString, QString> soundOverrides;
OrderedSet<PeerId> groupStickersSectionHidden;
base::flat_set<PeerId> groupStickersSectionHidden;
qint32 thirdSectionInfoEnabled = 0;
qint32 smallDialogsList = 0;
float64 dialogsWidthRatio = _variables.dialogsWidthRatio.current();
int thirdColumnWidth = _variables.thirdColumnWidth.current();
int thirdSectionExtendedBy = _variables.thirdSectionExtendedBy;
stream >> selectorTab;
stream >> lastSeenWarningSeen;
if (!stream.atEnd()) {
@@ -122,6 +136,21 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) {
}
}
}
if (!stream.atEnd()) {
stream >> thirdSectionInfoEnabled;
stream >> smallDialogsList;
}
if (!stream.atEnd()) {
qint32 value = 0;
stream >> value;
dialogsWidthRatio = snap(value / 1000000., 0., 1.);
stream >> value;
thirdColumnWidth = value;
stream >> value;
thirdSectionExtendedBy = value;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: Bad data for AuthSessionData::constructFromSerialized()"));
return;
@@ -151,6 +180,132 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) {
case RectPart::BottomRight: _variables.floatPlayerCorner = uncheckedCorner; break;
}
_variables.groupStickersSectionHidden = std::move(groupStickersSectionHidden);
_variables.thirdSectionInfoEnabled = thirdSectionInfoEnabled;
_variables.smallDialogsList = smallDialogsList;
_variables.dialogsWidthRatio = dialogsWidthRatio;
_variables.thirdColumnWidth = thirdColumnWidth;
_variables.thirdSectionExtendedBy = thirdSectionExtendedBy;
if (_variables.thirdSectionInfoEnabled) {
_variables.tabbedSelectorSectionEnabled = false;
}
}
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) {
_variables.tabbedSelectorSectionEnabled = enabled;
if (enabled) {
setThirdSectionInfoEnabled(false);
}
setTabbedReplacedWithInfo(false);
}
rpl::producer<bool> AuthSessionData::tabbedReplacedWithInfoValue() const {
return _tabbedReplacedWithInfoValue.events_starting_with(
tabbedReplacedWithInfo());
}
void AuthSessionData::setThirdSectionInfoEnabled(bool enabled) {
if (_variables.thirdSectionInfoEnabled != enabled) {
_variables.thirdSectionInfoEnabled = enabled;
if (enabled) {
setTabbedSelectorSectionEnabled(false);
}
setTabbedReplacedWithInfo(false);
_thirdSectionInfoEnabledValue.fire_copy(enabled);
}
}
rpl::producer<bool> AuthSessionData::thirdSectionInfoEnabledValue() const {
return _thirdSectionInfoEnabledValue.events_starting_with(
thirdSectionInfoEnabled());
}
void AuthSessionData::setTabbedReplacedWithInfo(bool enabled) {
if (_tabbedReplacedWithInfo != enabled) {
_tabbedReplacedWithInfo = enabled;
_tabbedReplacedWithInfoValue.fire_copy(enabled);
}
}
QString AuthSessionData::getSoundPath(const QString &key) const {
@@ -161,6 +316,68 @@ QString AuthSessionData::getSoundPath(const QString &key) const {
return qsl(":/sounds/") + key + qsl(".mp3");
}
void AuthSessionData::setDialogsWidthRatio(float64 ratio) {
_variables.dialogsWidthRatio = ratio;
}
float64 AuthSessionData::dialogsWidthRatio() const {
return _variables.dialogsWidthRatio.current();
}
rpl::producer<float64> AuthSessionData::dialogsWidthRatioChanges() const {
return _variables.dialogsWidthRatio.changes();
}
void AuthSessionData::setThirdColumnWidth(int width) {
_variables.thirdColumnWidth = width;
}
int AuthSessionData::thirdColumnWidth() const {
return _variables.thirdColumnWidth.current();
}
rpl::producer<int> AuthSessionData::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;
}
AuthSession &Auth() {
auto result = Messenger::Instance().authSession();
Assert(result != nullptr);
@@ -174,6 +391,7 @@ AuthSession::AuthSession(UserId userId)
, _calls(std::make_unique<Calls::Instance>())
, _downloader(std::make_unique<Storage::Downloader>())
, _uploader(std::make_unique<Storage::Uploader>())
, _storage(std::make_unique<Storage::Facade>())
, _notifications(std::make_unique<Window::Notifications::System>(this)) {
Expects(_userId != 0);
_saveDataTimer.setCallback([this] {

View File

@@ -20,11 +20,16 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
#include <rpl/event_stream.h>
#include <rpl/filter.h>
#include <rpl/variable.h>
#include "base/timer.h"
#include "chat_helpers/stickers.h"
namespace Storage {
class Downloader;
class Uploader;
class Facade;
} // namespace Storage
namespace Window {
@@ -55,18 +60,6 @@ public:
base::Observable<void> &moreChatsLoaded() {
return _moreChatsLoaded;
}
base::Observable<void> &stickersUpdated() {
return _stickersUpdated;
}
base::Observable<void> &savedGifsUpdated() {
return _savedGifsUpdated;
}
base::Observable<not_null<History*>> &historyCleared() {
return _historyCleared;
}
base::Observable<not_null<const HistoryItem*>> &repaintLogEntry() {
return _repaintLogEntry;
}
base::Observable<void> &pendingHistoryResize() {
return _pendingHistoryResize;
}
@@ -77,9 +70,34 @@ public:
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 copyFrom(const AuthSessionData &other) {
_variables = other._variables;
void moveFrom(AuthSessionData &&other) {
_variables = std::move(other._variables);
}
QByteArray serialize() const;
void constructFromSerialized(const QByteArray &serialized);
@@ -99,8 +117,28 @@ public:
bool tabbedSelectorSectionEnabled() const {
return _variables.tabbedSelectorSectionEnabled;
}
void setTabbedSelectorSectionEnabled(bool enabled) {
_variables.tabbedSelectorSectionEnabled = enabled;
void setTabbedSelectorSectionEnabled(bool enabled);
bool thirdSectionInfoEnabled() const {
return _variables.thirdSectionInfoEnabled;
}
void setThirdSectionInfoEnabled(bool enabled);
rpl::producer<bool> thirdSectionInfoEnabledValue() const;
int thirdSectionExtendedBy() const {
return _variables.thirdSectionExtendedBy;
}
void setThirdSectionExtendedBy(int savedValue) {
_variables.thirdSectionExtendedBy = savedValue;
}
bool tabbedReplacedWithInfo() const {
return _tabbedReplacedWithInfo;
}
void setTabbedReplacedWithInfo(bool enabled);
rpl::producer<bool> tabbedReplacedWithInfoValue() const;
void setSmallDialogsList(bool enabled) {
_variables.smallDialogsList = enabled;
}
bool smallDialogsList() const {
return _variables.smallDialogsList;
}
void setLastTimeVideoPlayedAt(TimeMs time) {
_lastTimeVideoPlayedAt = time;
@@ -133,6 +171,17 @@ public:
RectPart floatPlayerCorner() const {
return _variables.floatPlayerCorner;
}
void setDialogsWidthRatio(float64 ratio);
float64 dialogsWidthRatio() const;
rpl::producer<float64> dialogsWidthRatioChanges() const;
void setThirdColumnWidth(int width);
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);
}
@@ -142,30 +191,140 @@ 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;
private:
struct Variables {
Variables();
static constexpr auto kDefaultDialogsWidthRatio = 5. / 14;
static constexpr auto kDefaultThirdColumnWidth = 0;
bool lastSeenWarningSeen = false;
ChatHelpers::SelectorTab selectorTab;
bool tabbedSelectorSectionEnabled = true;
ChatHelpers::SelectorTab selectorTab; // per-window
bool tabbedSelectorSectionEnabled = false; // per-window
int tabbedSelectorSectionTooltipShown = 0;
QMap<QString, QString> soundOverrides;
Window::Column floatPlayerColumn;
RectPart floatPlayerCorner;
OrderedSet<PeerId> groupStickersSectionHidden;
Window::Column floatPlayerColumn; // per-window
RectPart floatPlayerCorner; // per-window
base::flat_set<PeerId> groupStickersSectionHidden;
bool thirdSectionInfoEnabled = true; // per-window
bool smallDialogsList = false; // per-window
int thirdSectionExtendedBy = -1; // per-window
rpl::variable<float64> dialogsWidthRatio
= kDefaultDialogsWidthRatio; // per-window
rpl::variable<int> thirdColumnWidth
= 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> _stickersUpdated;
base::Observable<void> _savedGifsUpdated;
base::Observable<not_null<History*>> _historyCleared;
base::Observable<not_null<const HistoryItem*>> _repaintLogEntry;
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;
Variables _variables;
TimeMs _lastTimeVideoPlayedAt = 0;
@@ -199,6 +358,9 @@ public:
Storage::Uploader &uploader() {
return *_uploader;
}
Storage::Facade &storage() {
return *_storage;
}
base::Observable<void> &downloaderTaskFinished();
@@ -209,7 +371,7 @@ public:
AuthSessionData &data() {
return _data;
}
void saveDataDelayed(TimeMs delay);
void saveDataDelayed(TimeMs delay = kDefaultSaveDelay);
ApiWrap &api() {
return *_api;
@@ -223,11 +385,13 @@ public:
void checkAutoLockIn(TimeMs time);
base::Observable<DocumentData*> documentUpdated;
base::Observable<std::pair<HistoryItem*, MsgId>> messageIdChanging;
base::Observable<std::pair<not_null<HistoryItem*>, MsgId>> messageIdChanging;
~AuthSession();
private:
static constexpr auto kDefaultSaveDelay = TimeMs(1000);
const UserId _userId = 0;
AuthSessionData _data;
base::Timer _saveDataTimer;
@@ -239,6 +403,7 @@ private:
const std::unique_ptr<Calls::Instance> _calls;
const std::unique_ptr<Storage::Downloader> _downloader;
const std::unique_ptr<Storage::Uploader> _uploader;
const std::unique_ptr<Storage::Facade> _storage;
const std::unique_ptr<Window::Notifications::System> _notifications;
};

View File

@@ -22,19 +22,19 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace base {
template <typename Range, typename Method>
decltype(auto) for_each(Range &&range, Method &&method) {
return std::for_each(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Method>(method));
template <typename Type>
inline Type take(Type &value) {
return std::exchange(value, Type {});
}
template <typename Method>
decltype(auto) for_each_apply(Method &&method) {
return [&method](auto &&range) {
return for_each(std::forward<decltype(range)>(range), std::forward<Method>(method));
};
template <typename Type>
inline Type duplicate(const Type &value) {
return value;
}
template <typename Type, size_t Size>
inline constexpr size_t array_size(const Type(&)[Size]) {
return Size;
}
} // namespace base

View File

@@ -0,0 +1,63 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#include "catch.hpp"
#include "base/index_based_iterator.h"
TEST_CASE("index_based_iterator tests", "[base::algorithm]") {
auto v = std::vector<int>();
v.insert(v.end(), { 1, 2, 3, 4, 5, 4, 3, 2, 1 });
auto push_back_safe_remove_if = [](auto &v, auto predicate) {
auto begin = base::index_based_begin(v);
auto end = base::index_based_end(v);
auto from = std::remove_if(begin, end, predicate);
if (from != end) {
auto newEnd = base::index_based_end(v);
if (newEnd != end) {
REQUIRE(newEnd > end);
while (end != newEnd) {
*from++ = *end++;
}
}
v.erase(from.base(), newEnd.base());
}
};
SECTION("allows to push_back from predicate") {
push_back_safe_remove_if(v, [&v](int value) {
v.push_back(value);
return (value % 2) == 1;
});
auto expected = std::vector<int> { 2, 4, 4, 2, 1, 2, 3, 4, 5, 4, 3, 2, 1 };
REQUIRE(v == expected);
}
SECTION("allows to push_back while removing all") {
push_back_safe_remove_if(v, [&v](int value) {
if (value == 5) {
v.push_back(value);
}
return true;
});
auto expected = std::vector<int> { 5 };
REQUIRE(v == expected);
}
}

View File

@@ -29,7 +29,7 @@ namespace assertion {
void log(const char *message, const char *file, int line);
// Release build assertions.
inline void noop() {
inline constexpr void noop() {
}
[[noreturn]] inline void fail(const char *message, const char *file, int line) {
@@ -43,10 +43,20 @@ inline void noop() {
std::abort();
}
inline void validate(bool condition, const char *message, const char *file, int line) {
#ifndef GSL_UNLIKELY
#define DEFINED_GSL_UNLIKELY_
#define GSL_UNLIKELY(expression) (expression)
#endif // GSL_UNLIKELY
inline constexpr void validate(bool condition, const char *message, const char *file, int line) {
(GSL_UNLIKELY(!(condition))) ? fail(message, file, line) : noop();
}
#ifdef DEFINED_GSL_UNLIKELY_
#undef GSL_UNLIKELY
#undef DEFINED_GSL_UNLIKELY_
#endif // DEFINED_GSL_UNLIKELY_
} // namespace assertion
} // namespace base

View File

@@ -64,12 +64,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#error Please add support for your architecture in base/build_config.h
#endif
#if defined(COMPILER_GCC) || defined(COMPILER_CLANG)
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define WARN_UNUSED_RESULT
#endif
#if defined(__GNUC__)
#define FORCE_INLINE inline __attribute__((always_inline))
#elif defined(_MSC_VER)

View File

@@ -0,0 +1,60 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
namespace base {
template <typename Enum>
class enum_mask {
using Type = std::uint32_t;
public:
static_assert(static_cast<int>(Enum::kCount) <= 32, "We have only 32 bit.");
enum_mask() = default;
enum_mask(Enum value) : _value(ToBit(value)) {
}
enum_mask added(enum_mask other) const {
auto result = *this;
result.set(other);
return result;
}
void set(enum_mask other) {
_value |= other._value;
}
bool test(Enum value) const {
return _value & ToBit(value);
}
explicit operator bool() const {
return _value != 0;
}
private:
inline static Type ToBit(Enum value) {
return 1 << static_cast<Type>(value);
}
Type _value = 0;
};
} // namespace base

View File

@@ -22,12 +22,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include <type_traits>
#if defined _MSC_VER && _MSC_VER < 1910
#define FLAGS_CONSTEXPR
#else // MSVS2015
#define FLAGS_CONSTEXPR constexpr
#endif // MSVS2015
namespace base {
template <typename EnumType>
@@ -69,9 +63,11 @@ public:
constexpr flags() = default;
constexpr flags(details::flags_zero_helper) noexcept {
}
constexpr flags(Enum value) noexcept : _value(static_cast<Type>(value)) {
constexpr flags(Enum value) noexcept
: _value(static_cast<Type>(value)) {
}
explicit constexpr flags(Type value) noexcept : _value(value) {
static constexpr flags from_raw(Type value) noexcept {
return flags(static_cast<Enum>(value));
}
constexpr auto value() const noexcept {
@@ -81,40 +77,40 @@ public:
return value();
}
FLAGS_CONSTEXPR auto &operator|=(flags b) noexcept {
constexpr auto &operator|=(flags b) noexcept {
_value |= b.value();
return *this;
}
FLAGS_CONSTEXPR auto &operator&=(flags b) noexcept {
constexpr auto &operator&=(flags b) noexcept {
_value &= b.value();
return *this;
}
FLAGS_CONSTEXPR auto &operator^=(flags b) noexcept {
constexpr auto &operator^=(flags b) noexcept {
_value ^= b.value();
return *this;
}
FLAGS_CONSTEXPR auto operator~() const noexcept {
return flags(~value());
constexpr auto operator~() const noexcept {
return from_raw(~value());
}
FLAGS_CONSTEXPR auto operator|(flags b) const noexcept {
constexpr auto operator|(flags b) const noexcept {
return (flags(*this) |= b);
}
FLAGS_CONSTEXPR auto operator&(flags b) const noexcept {
constexpr auto operator&(flags b) const noexcept {
return (flags(*this) &= b);
}
FLAGS_CONSTEXPR auto operator^(flags b) const noexcept {
constexpr auto operator^(flags b) const noexcept {
return (flags(*this) ^= b);
}
FLAGS_CONSTEXPR auto operator|(Enum b) const noexcept {
constexpr auto operator|(Enum b) const noexcept {
return (flags(*this) |= b);
}
FLAGS_CONSTEXPR auto operator&(Enum b) const noexcept {
constexpr auto operator&(Enum b) const noexcept {
return (flags(*this) &= b);
}
FLAGS_CONSTEXPR auto operator^(Enum b) const noexcept {
constexpr auto operator^(Enum b) const noexcept {
return (flags(*this) ^= b);
}
@@ -296,8 +292,6 @@ inline constexpr auto operator>=(ExtendedEnum a, flags<extended_flags_t<Extended
} // namespace base
#undef FLAGS_CONSTEXPR
template <typename Enum,
typename = std::enable_if_t<std::is_enum<Enum>::value>,
typename = std::enable_if_t<is_flag_type(Enum{})>>

View File

@@ -21,149 +21,267 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once
#include <deque>
#include <algorithm>
#include "base/optional.h"
namespace base {
template <typename Key, typename Type>
template <
typename Key,
typename Type,
typename Compare = std::less<>>
class flat_map;
template <typename Key, typename Type>
template <
typename Key,
typename Type,
typename Compare = std::less<>>
class flat_multi_map;
template <typename Key, typename Type, typename iterator_impl, typename pointer_impl, typename reference_impl>
template <
typename Me,
typename Key,
typename Type,
typename iterator_impl,
typename pointer_impl,
typename reference_impl>
class flat_multi_map_iterator_base_impl;
template <typename Key, typename Type, typename iterator_impl, typename pointer_impl, typename reference_impl>
template <typename Key, typename Value>
struct flat_multi_map_pair_type {
using first_type = const Key;
using second_type = Value;
constexpr flat_multi_map_pair_type()
: first()
, second() {
}
template <typename OtherKey, typename OtherValue>
constexpr flat_multi_map_pair_type(OtherKey &&key, OtherValue &&value)
: first(std::forward<OtherKey>(key))
, second(std::forward<OtherValue>(value)) {
}
flat_multi_map_pair_type(const flat_multi_map_pair_type&) = default;
flat_multi_map_pair_type(flat_multi_map_pair_type&&) = default;
flat_multi_map_pair_type &operator=(const flat_multi_map_pair_type&) = delete;
flat_multi_map_pair_type &operator=(flat_multi_map_pair_type &&other) {
const_cast<Key&>(first) = other.first;
second = std::move(other.second);
return *this;
}
void swap(flat_multi_map_pair_type &other) {
using std::swap;
if (this != &other) {
std::swap(
const_cast<Key&>(first),
const_cast<Key&>(other.first));
std::swap(second, other.second);
}
}
const Key first;
Value second;
};
template <
typename Me,
typename Key,
typename Type,
typename iterator_impl,
typename pointer_impl,
typename reference_impl>
class flat_multi_map_iterator_base_impl {
public:
using iterator_category = typename iterator_impl::iterator_category;
using value_type = typename flat_multi_map<Key, Type>::value_type;
using pair_type = flat_multi_map_pair_type<Key, Type>;
using value_type = pair_type;
using difference_type = typename iterator_impl::difference_type;
using pointer = pointer_impl;
using const_pointer = typename flat_multi_map<Key, Type>::const_pointer;
using reference = reference_impl;
using const_reference = typename flat_multi_map<Key, Type>::const_reference;
flat_multi_map_iterator_base_impl(iterator_impl impl = iterator_impl()) : _impl(impl) {
flat_multi_map_iterator_base_impl(iterator_impl impl = iterator_impl())
: _impl(impl) {
}
reference operator*() {
reference operator*() const {
return *_impl;
}
const_reference operator*() const {
return *_impl;
}
pointer operator->() {
pointer operator->() const {
return std::addressof(**this);
}
const_pointer operator->() const {
return std::addressof(**this);
}
flat_multi_map_iterator_base_impl &operator++() {
Me &operator++() {
++_impl;
return *this;
return static_cast<Me&>(*this);
}
flat_multi_map_iterator_base_impl operator++(int) {
Me operator++(int) {
return _impl++;
}
flat_multi_map_iterator_base_impl &operator--() {
Me &operator--() {
--_impl;
return *this;
return static_cast<Me&>(*this);
}
flat_multi_map_iterator_base_impl operator--(int) {
Me operator--(int) {
return _impl--;
}
flat_multi_map_iterator_base_impl &operator+=(difference_type offset) {
Me &operator+=(difference_type offset) {
_impl += offset;
return *this;
return static_cast<Me&>(*this);
}
flat_multi_map_iterator_base_impl operator+(difference_type offset) const {
Me operator+(difference_type offset) const {
return _impl + offset;
}
flat_multi_map_iterator_base_impl &operator-=(difference_type offset) {
Me &operator-=(difference_type offset) {
_impl -= offset;
return *this;
return static_cast<Me&>(*this);
}
flat_multi_map_iterator_base_impl operator-(difference_type offset) const {
Me operator-(difference_type offset) const {
return _impl - offset;
}
difference_type operator-(const flat_multi_map_iterator_base_impl &right) const {
template <
typename other_me,
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
difference_type operator-(
const flat_multi_map_iterator_base_impl<
other_me,
Key,
Type,
other_iterator_impl,
other_pointer_impl,
other_reference_impl> &right) const {
return _impl - right._impl;
}
reference operator[](difference_type offset) {
return _impl[offset];
}
const_reference operator[](difference_type offset) const {
reference operator[](difference_type offset) const {
return _impl[offset];
}
bool operator==(const flat_multi_map_iterator_base_impl &right) const {
template <
typename other_me,
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
bool operator==(
const flat_multi_map_iterator_base_impl<
other_me,
Key,
Type,
other_iterator_impl,
other_pointer_impl,
other_reference_impl> &right) const {
return _impl == right._impl;
}
bool operator!=(const flat_multi_map_iterator_base_impl &right) const {
template <
typename other_me,
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
bool operator!=(
const flat_multi_map_iterator_base_impl<
other_me,
Key,
Type,
other_iterator_impl,
other_pointer_impl,
other_reference_impl> &right) const {
return _impl != right._impl;
}
bool operator<(const flat_multi_map_iterator_base_impl &right) const {
template <
typename other_me,
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
bool operator<(
const flat_multi_map_iterator_base_impl<
other_me,
Key,
Type,
other_iterator_impl,
other_pointer_impl,
other_reference_impl> &right) const {
return _impl < right._impl;
}
private:
iterator_impl _impl;
friend class flat_multi_map<Key, Type>;
template <
typename OtherKey,
typename OtherType,
typename OtherCompare>
friend class flat_multi_map;
template <
typename OtherMe,
typename OtherKey,
typename OtherType,
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
friend class flat_multi_map_iterator_base_impl;
};
template <typename Key, typename Type>
template <typename Key, typename Type, typename Compare>
class flat_multi_map {
using self = flat_multi_map<Key, Type>;
class key_const_wrap {
public:
key_const_wrap(const Key &value) : _value(value) {
}
key_const_wrap(Key &&value) : _value(std::move(value)) {
}
inline operator const Key&() const {
return _value;
}
public:
class iterator;
class const_iterator;
class reverse_iterator;
class const_reverse_iterator;
friend inline bool operator<(const Key &a, const key_const_wrap &b) {
return a < ((const Key&)b);
}
friend inline bool operator<(const key_const_wrap &a, const Key &b) {
return ((const Key&)a) < b;
}
friend inline bool operator<(const key_const_wrap &a, const key_const_wrap &b) {
return ((const Key&)a) < ((const Key&)b);
}
private:
using pair_type = flat_multi_map_pair_type<Key, Type>;
using impl_t = std::deque<pair_type>;
private:
Key _value;
};
using pair_type = std::pair<key_const_wrap, Type>;
using impl = std::deque<pair_type>;
using iterator_base = flat_multi_map_iterator_base_impl<Key, Type, typename impl::iterator, pair_type*, pair_type&>;
using const_iterator_base = flat_multi_map_iterator_base_impl<Key, Type, typename impl::const_iterator, const pair_type*, const pair_type&>;
using reverse_iterator_base = flat_multi_map_iterator_base_impl<Key, Type, typename impl::reverse_iterator, pair_type*, pair_type&>;
using const_reverse_iterator_base = flat_multi_map_iterator_base_impl<Key, Type, typename impl::const_reverse_iterator, const pair_type*, const pair_type&>;
using iterator_base = flat_multi_map_iterator_base_impl<
iterator,
Key,
Type,
typename impl_t::iterator,
pair_type*,
pair_type&>;
using const_iterator_base = flat_multi_map_iterator_base_impl<
const_iterator,
Key,
Type,
typename impl_t::const_iterator,
const pair_type*,
const pair_type&>;
using reverse_iterator_base = flat_multi_map_iterator_base_impl<
reverse_iterator,
Key,
Type,
typename impl_t::reverse_iterator,
pair_type*,
pair_type&>;
using const_reverse_iterator_base = flat_multi_map_iterator_base_impl<
const_reverse_iterator,
Key,
Type,
typename impl_t::const_reverse_iterator,
const pair_type*,
const pair_type&>;
public:
using value_type = pair_type;
using size_type = typename impl::size_type;
using difference_type = typename impl::difference_type;
using size_type = typename impl_t::size_type;
using difference_type = typename impl_t::difference_type;
using pointer = pair_type*;
using const_pointer = const pair_type*;
using reference = pair_type&;
using const_reference = const pair_type&;
class const_iterator;
class iterator : public iterator_base {
public:
using iterator_base::iterator_base;
iterator() = default;
iterator(const iterator_base &other) : iterator_base(other) {
}
friend class const_iterator;
@@ -172,16 +290,17 @@ public:
class const_iterator : public const_iterator_base {
public:
using const_iterator_base::const_iterator_base;
const_iterator() = default;
const_iterator(const_iterator_base other) : const_iterator_base(other) {
}
const_iterator(const iterator &other) : const_iterator_base(other._impl) {
}
};
class const_reverse_iterator;
class reverse_iterator : public reverse_iterator_base {
public:
using reverse_iterator_base::reverse_iterator_base;
reverse_iterator() = default;
reverse_iterator(reverse_iterator_base other) : reverse_iterator_base(other) {
}
friend class const_reverse_iterator;
@@ -190,6 +309,7 @@ public:
class const_reverse_iterator : public const_reverse_iterator_base {
public:
using const_reverse_iterator_base::const_reverse_iterator_base;
const_reverse_iterator() = default;
const_reverse_iterator(const_reverse_iterator_base other) : const_reverse_iterator_base(other) {
}
const_reverse_iterator(const reverse_iterator &other) : const_reverse_iterator_base(other._impl) {
@@ -198,50 +318,50 @@ public:
};
size_type size() const {
return _impl.size();
return impl().size();
}
bool empty() const {
return _impl.empty();
return impl().empty();
}
void clear() {
_impl.clear();
impl().clear();
}
iterator begin() {
return _impl.begin();
return impl().begin();
}
iterator end() {
return _impl.end();
return impl().end();
}
const_iterator begin() const {
return _impl.begin();
return impl().begin();
}
const_iterator end() const {
return _impl.end();
return impl().end();
}
const_iterator cbegin() const {
return _impl.cbegin();
return impl().cbegin();
}
const_iterator cend() const {
return _impl.cend();
return impl().cend();
}
reverse_iterator rbegin() {
return _impl.rbegin();
return impl().rbegin();
}
reverse_iterator rend() {
return _impl.rend();
return impl().rend();
}
const_reverse_iterator rbegin() const {
return _impl.rbegin();
return impl().rbegin();
}
const_reverse_iterator rend() const {
return _impl.rend();
return impl().rend();
}
const_reverse_iterator crbegin() const {
return _impl.crbegin();
return impl().crbegin();
}
const_reverse_iterator crend() const {
return _impl.crend();
return impl().crend();
}
reference front() {
@@ -258,26 +378,26 @@ public:
}
iterator insert(const value_type &value) {
if (empty() || (value.first < front().first)) {
_impl.push_front(value);
if (empty() || compare()(value.first, front().first)) {
impl().push_front(value);
return begin();
} else if (!(value.first < back().first)) {
_impl.push_back(value);
} else if (!compare()(value.first, back().first)) {
impl().push_back(value);
return (end() - 1);
}
auto where = getUpperBound(value.first);
return _impl.insert(where, value);
return impl().insert(where, value);
}
iterator insert(value_type &&value) {
if (empty() || (value.first < front().first)) {
_impl.push_front(std::move(value));
if (empty() || compare()(value.first, front().first)) {
impl().push_front(std::move(value));
return begin();
} else if (!(value.first < back().first)) {
_impl.push_back(std::move(value));
} else if (!compare()(value.first, back().first)) {
impl().push_back(std::move(value));
return (end() - 1);
}
auto where = getUpperBound(value.first);
return _impl.insert(where, std::move(value));
return impl().insert(where, std::move(value));
}
template <typename... Args>
iterator emplace(Args&&... args) {
@@ -285,56 +405,66 @@ public:
}
bool removeOne(const Key &key) {
if (empty() || (key < front().first) || (back().first < key)) {
if (empty()
|| compare()(key, front().first)
|| compare()(back().first, key)) {
return false;
}
auto where = getLowerBound(key);
if (key < where->first) {
if (compare()(key, where->first)) {
return false;
}
_impl.erase(where);
impl().erase(where);
return true;
}
int removeAll(const Key &key) {
if (empty() || (key < front().first) || (back().first < key)) {
if (empty()
|| compare()(key, front().first)
|| compare()(back().first, key)) {
return 0;
}
auto range = getEqualRange(key);
if (range.first == range.second) {
return 0;
}
_impl.erase(range.first, range.second);
impl().erase(range.first, range.second);
return (range.second - range.first);
}
iterator erase(iterator where) {
return _impl.erase(where._impl);
iterator erase(const_iterator where) {
return impl().erase(where._impl);
}
iterator erase(iterator from, iterator till) {
return _impl.erase(from._impl, till._impl);
iterator erase(const_iterator from, const_iterator till) {
return impl().erase(from._impl, till._impl);
}
iterator findFirst(const Key &key) {
if (empty() || (key < front().first) || (back().first < key)) {
if (empty()
|| compare()(key, front().first)
|| compare()(back().first, key)) {
return end();
}
auto where = getLowerBound(key);
return (key < where->first) ? _impl.end() : where;
return compare()(key, where->first) ? impl().end() : where;
}
const_iterator findFirst(const Key &key) const {
if (empty() || (key < front().first) || (back().first < key)) {
if (empty()
|| compare()(key, front().first)
|| compare()(back().first, key)) {
return end();
}
auto where = getLowerBound(key);
return (key < where->first) ? _impl.end() : where;
return compare()(key, where->first) ? impl().end() : where;
}
bool contains(const Key &key) const {
return findFirst(key) != end();
}
int count(const Key &key) const {
if (empty() || (key < front().first) || (back().first < key)) {
if (empty()
|| compare()(key, front().first)
|| compare()(back().first, key)) {
return 0;
}
auto range = getEqualRange(key);
@@ -342,80 +472,225 @@ public:
}
private:
impl _impl;
friend class flat_map<Key, Type>;
friend class flat_map<Key, Type, Compare>;
struct Comparator {
inline bool operator()(const pair_type &a, const Key &b) {
return a.first < b;
struct transparent_compare : Compare {
inline constexpr const Compare &initial() const noexcept {
return *this;
}
inline bool operator()(const Key &a, const pair_type &b) {
return a < b.first;
template <
typename OtherType1,
typename OtherType2,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType1>, pair_type> &&
!std::is_same_v<std::decay_t<OtherType2>, pair_type>>>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const {
return initial()(
std::forward<OtherType1>(a),
std::forward<OtherType2>(b));
}
template <
typename OtherType1,
typename OtherType2>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const -> std::enable_if_t<
std::is_same_v<std::decay_t<OtherType1>, pair_type> &&
std::is_same_v<std::decay_t<OtherType2>, pair_type>, bool> {
return initial()(a.first, b.first);
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
const pair_type &a,
OtherType &&b) const {
return operator()(a.first, std::forward<OtherType>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
OtherType &&a,
const pair_type &b) const {
return operator()(std::forward<OtherType>(a), b.first);
}
};
typename impl::iterator getLowerBound(const Key &key) {
return std::lower_bound(_impl.begin(), _impl.end(), key, Comparator());
struct Data : transparent_compare {
template <typename ...Args>
Data(Args &&...args)
: elements(std::forward<Args>(args)...) {
}
impl_t elements;
};
Data _data;
const transparent_compare &compare() const noexcept {
return _data;
}
typename impl::const_iterator getLowerBound(const Key &key) const {
return std::lower_bound(_impl.begin(), _impl.end(), key, Comparator());
const impl_t &impl() const noexcept {
return _data.elements;
}
typename impl::iterator getUpperBound(const Key &key) {
return std::upper_bound(_impl.begin(), _impl.end(), key, Comparator());
impl_t &impl() noexcept {
return _data.elements;
}
typename impl::const_iterator getUpperBound(const Key &key) const {
return std::upper_bound(_impl.begin(), _impl.end(), key, Comparator());
typename impl_t::iterator getLowerBound(const Key &key) {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
key,
compare());
}
std::pair<typename impl::iterator, typename impl::iterator> getEqualRange(const Key &key) {
return std::equal_range(_impl.begin(), _impl.end(), key, Comparator());
typename impl_t::const_iterator getLowerBound(const Key &key) const {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
key,
compare());
}
std::pair<typename impl::const_iterator, typename impl::const_iterator> getEqualRange(const Key &key) const {
return std::equal_range(_impl.begin(), _impl.end(), key, Comparator());
typename impl_t::iterator getUpperBound(const Key &key) {
return std::upper_bound(
std::begin(impl()),
std::end(impl()),
key,
compare());
}
typename impl_t::const_iterator getUpperBound(const Key &key) const {
return std::upper_bound(
std::begin(impl()),
std::end(impl()),
key,
compare());
}
std::pair<
typename impl_t::iterator,
typename impl_t::iterator
> getEqualRange(const Key &key) {
return std::equal_range(
std::begin(impl()),
std::end(impl()),
key,
compare());
}
std::pair<
typename impl_t::const_iterator,
typename impl_t::const_iterator
> getEqualRange(const Key &key) const {
return std::equal_range(
std::begin(impl()),
std::end(impl()),
key,
compare());
}
};
template <typename Key, typename Type>
class flat_map : public flat_multi_map<Key, Type> {
using parent = flat_multi_map<Key, Type>;
template <typename Key, typename Type, typename Compare>
class flat_map : private flat_multi_map<Key, Type, Compare> {
using parent = flat_multi_map<Key, Type, Compare>;
using pair_type = typename parent::pair_type;
public:
using parent::parent;
using value_type = typename parent::value_type;
using size_type = typename parent::size_type;
using difference_type = typename parent::difference_type;
using pointer = typename parent::pointer;
using const_pointer = typename parent::const_pointer;
using reference = typename parent::reference;
using const_reference = typename parent::const_reference;
using iterator = typename parent::iterator;
using const_iterator = typename parent::const_iterator;
using value_type = typename parent::value_type;
using reverse_iterator = typename parent::reverse_iterator;
using const_reverse_iterator = typename parent::const_reverse_iterator;
iterator insert(const value_type &value) {
if (this->empty() || (value.first < this->front().first)) {
this->_impl.push_front(value);
return this->begin();
} else if (this->back().first < value.first) {
this->_impl.push_back(value);
return (this->end() - 1);
using parent::parent;
using parent::size;
using parent::empty;
using parent::clear;
using parent::begin;
using parent::end;
using parent::cbegin;
using parent::cend;
using parent::rbegin;
using parent::rend;
using parent::crbegin;
using parent::crend;
using parent::front;
using parent::back;
using parent::erase;
using parent::contains;
std::pair<iterator, bool> insert(const value_type &value) {
if (this->empty() || this->compare()(value.first, this->front().first)) {
this->impl().push_front(value);
return { this->begin(), true };
} else if (this->compare()(this->back().first, value.first)) {
this->impl().push_back(value);
return { this->end() - 1, true };
}
auto where = this->getLowerBound(value.first);
if (value.first < where->first) {
return this->_impl.insert(where, value);
if (this->compare()(value.first, where->first)) {
return { this->impl().insert(where, value), true };
}
return this->end();
return { where, false };
}
iterator insert(value_type &&value) {
if (this->empty() || (value.first < this->front().first)) {
this->_impl.push_front(std::move(value));
return this->begin();
} else if (this->back().first < value.first) {
this->_impl.push_back(std::move(value));
return (this->end() - 1);
std::pair<iterator, bool> insert(value_type &&value) {
if (this->empty() || this->compare()(value.first, this->front().first)) {
this->impl().push_front(std::move(value));
return { this->begin(), true };
} else if (this->compare()(this->back().first, value.first)) {
this->impl().push_back(std::move(value));
return { this->end() - 1, true };
}
auto where = this->getLowerBound(value.first);
if (value.first < where->first) {
return this->_impl.insert(where, std::move(value));
if (this->compare()(value.first, where->first)) {
return { this->impl().insert(where, std::move(value)), true };
}
return this->end();
return { where, false };
}
template <typename... Args>
iterator emplace(Args&&... args) {
return this->insert(value_type(std::forward<Args>(args)...));
std::pair<iterator, bool> emplace(
const Key &key,
Args&&... args) {
return this->insert(value_type(
key,
Type(std::forward<Args>(args)...)));
}
template <typename... Args>
std::pair<iterator, bool> try_emplace(
const Key &key,
Args&&... args) {
if (this->empty() || this->compare()(key, this->front().first)) {
this->impl().push_front(value_type(
key,
Type(std::forward<Args>(args)...)));
return { this->begin(), true };
} else if (this->compare()(this->back().first, key)) {
this->impl().push_back(value_type(
key,
Type(std::forward<Args>(args)...)));
return { this->end() - 1, true };
}
auto where = this->getLowerBound(key);
if (this->compare()(key, where->first)) {
return {
this->impl().insert(
where,
value_type(
key,
Type(std::forward<Args>(args)...))),
true
};
}
return { where, false };
}
bool remove(const Key &key) {
@@ -430,16 +705,16 @@ public:
}
Type &operator[](const Key &key) {
if (this->empty() || (key < this->front().first)) {
this->_impl.push_front({ key, Type() });
if (this->empty() || this->compare()(key, this->front().first)) {
this->impl().push_front({ key, Type() });
return this->front().second;
} else if (this->back().first < key) {
this->_impl.push_back({ key, Type() });
} else if (this->compare()(this->back().first, key)) {
this->impl().push_back({ key, Type() });
return this->back().second;
}
auto where = this->getLowerBound(key);
if (key < where->first) {
return this->_impl.insert(where, { key, Type() })->second;
if (this->compare()(key, where->first)) {
return this->impl().insert(where, { key, Type() })->second;
}
return where->second;
}

View File

@@ -23,6 +23,15 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "base/flat_map.h"
#include <string>
struct int_wrap {
int value;
};
struct int_wrap_comparator {
inline bool operator()(const int_wrap &a, const int_wrap &b) const {
return a.value < b.value;
}
};
using namespace std;
TEST_CASE("flat_maps should keep items sorted by key", "[flat_map]") {
@@ -49,3 +58,28 @@ TEST_CASE("flat_maps should keep items sorted by key", "[flat_map]") {
checkSorted();
}
}
TEST_CASE("flat_maps custom comparator", "[flat_map]") {
base::flat_map<int_wrap, string, int_wrap_comparator> v;
v.emplace({ 0 }, "a");
v.emplace({ 5 }, "b");
v.emplace({ 4 }, "d");
v.emplace({ 2 }, "e");
auto checkSorted = [&] {
auto prev = v.begin();
REQUIRE(prev != v.end());
for (auto i = prev + 1; i != v.end(); prev = i, ++i) {
REQUIRE(int_wrap_comparator()(prev->first, i->first));
}
};
REQUIRE(v.size() == 4);
checkSorted();
SECTION("adding item puts it in the right position") {
v.emplace({ 3 }, "c");
REQUIRE(v.size() == 5);
REQUIRE(v.find({ 3 }) != v.end());
checkSorted();
}
}

View File

@@ -21,29 +21,39 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once
#include <deque>
#include <algorithm>
namespace base {
template <typename Type>
template <typename Type, typename Compare = std::less<>>
class flat_set;
template <typename Type>
template <typename Type, typename Compare = std::less<>>
class flat_multi_set;
template <typename Type, typename iterator_impl>
class flat_multi_set_iterator_base_impl;
class flat_multi_set_iterator_impl;
template <typename Type, typename iterator_impl>
class flat_multi_set_iterator_base_impl {
class flat_multi_set_iterator_impl {
public:
using iterator_category = typename iterator_impl::iterator_category;
using value_type = typename flat_multi_set<Type>::value_type;
using value_type = Type;
using difference_type = typename iterator_impl::difference_type;
using pointer = typename flat_multi_set<Type>::pointer;
using reference = typename flat_multi_set<Type>::reference;
using pointer = const Type*;
using reference = const Type&;
flat_multi_set_iterator_base_impl(iterator_impl impl = iterator_impl()) : _impl(impl) {
flat_multi_set_iterator_impl(
iterator_impl impl = iterator_impl())
: _impl(impl) {
}
template <typename other_iterator_impl>
flat_multi_set_iterator_impl(
const flat_multi_set_iterator_impl<
Type,
other_iterator_impl> &other)
: _impl(other._impl) {
}
reference operator*() const {
@@ -52,188 +62,192 @@ public:
pointer operator->() const {
return std::addressof(**this);
}
flat_multi_set_iterator_base_impl &operator++() {
flat_multi_set_iterator_impl &operator++() {
++_impl;
return *this;
}
flat_multi_set_iterator_base_impl operator++(int) {
flat_multi_set_iterator_impl operator++(int) {
return _impl++;
}
flat_multi_set_iterator_base_impl &operator--() {
flat_multi_set_iterator_impl &operator--() {
--_impl;
return *this;
}
flat_multi_set_iterator_base_impl operator--(int) {
flat_multi_set_iterator_impl operator--(int) {
return _impl--;
}
flat_multi_set_iterator_base_impl &operator+=(difference_type offset) {
flat_multi_set_iterator_impl &operator+=(difference_type offset) {
_impl += offset;
return *this;
}
flat_multi_set_iterator_base_impl operator+(difference_type offset) const {
flat_multi_set_iterator_impl operator+(difference_type offset) const {
return _impl + offset;
}
flat_multi_set_iterator_base_impl &operator-=(difference_type offset) {
flat_multi_set_iterator_impl &operator-=(difference_type offset) {
_impl -= offset;
return *this;
}
flat_multi_set_iterator_base_impl operator-(difference_type offset) const {
flat_multi_set_iterator_impl operator-(difference_type offset) const {
return _impl - offset;
}
difference_type operator-(const flat_multi_set_iterator_base_impl &right) const {
template <typename other_iterator_impl>
difference_type operator-(
const flat_multi_set_iterator_impl<
Type,
other_iterator_impl> &right) const {
return _impl - right._impl;
}
reference operator[](difference_type offset) const {
return _impl[offset];
}
bool operator==(const flat_multi_set_iterator_base_impl &right) const {
template <typename other_iterator_impl>
bool operator==(
const flat_multi_set_iterator_impl<
Type,
other_iterator_impl> &right) const {
return _impl == right._impl;
}
bool operator!=(const flat_multi_set_iterator_base_impl &right) const {
template <typename other_iterator_impl>
bool operator!=(
const flat_multi_set_iterator_impl<
Type,
other_iterator_impl> &right) const {
return _impl != right._impl;
}
bool operator<(const flat_multi_set_iterator_base_impl &right) const {
template <typename other_iterator_impl>
bool operator<(
const flat_multi_set_iterator_impl<
Type,
other_iterator_impl> &right) const {
return _impl < right._impl;
}
private:
iterator_impl _impl;
friend class flat_multi_set<Type>;
template <typename OtherType, typename OtherCompare>
friend class flat_multi_set;
template <typename OtherType, typename OtherCompare>
friend class flat_set;
template <
typename OtherType,
typename other_iterator_impl>
friend class flat_multi_set_iterator_impl;
Type &wrapped() {
return _impl->wrapped();
}
};
template <typename Type>
class flat_multi_set_const_wrap {
public:
constexpr flat_multi_set_const_wrap(const Type &value)
: _value(value) {
}
constexpr flat_multi_set_const_wrap(Type &&value)
: _value(std::move(value)) {
}
inline constexpr operator const Type&() const {
return _value;
}
constexpr Type &wrapped() {
return _value;
}
private:
Type _value;
};
template <typename Type, typename Compare>
class flat_multi_set {
using self = flat_multi_set<Type>;
class const_wrap {
public:
const_wrap(const Type &value) : _value(value) {
}
const_wrap(Type &&value) : _value(std::move(value)) {
}
inline operator const Type&() const {
return _value;
}
friend inline bool operator<(const Type &a, const const_wrap &b) {
return a < ((const Type&)b);
}
friend inline bool operator<(const const_wrap &a, const Type &b) {
return ((const Type&)a) < b;
}
friend inline bool operator<(const const_wrap &a, const const_wrap &b) {
return ((const Type&)a) < ((const Type&)b);
}
private:
Type _value;
};
using impl = std::deque<const_wrap>;
using iterator_base = flat_multi_set_iterator_base_impl<Type, typename impl::iterator>;
using const_iterator_base = flat_multi_set_iterator_base_impl<Type, typename impl::const_iterator>;
using reverse_iterator_base = flat_multi_set_iterator_base_impl<Type, typename impl::reverse_iterator>;
using const_reverse_iterator_base = flat_multi_set_iterator_base_impl<Type, typename impl::const_reverse_iterator>;
using const_wrap = flat_multi_set_const_wrap<Type>;
using impl_t = std::deque<const_wrap>;
public:
using value_type = Type;
using size_type = typename impl::size_type;
using difference_type = typename impl::difference_type;
using size_type = typename impl_t::size_type;
using difference_type = typename impl_t::difference_type;
using pointer = const Type*;
using reference = const Type&;
class const_iterator;
class iterator : public iterator_base {
public:
using iterator_base::iterator_base;
iterator(const iterator_base &other) : iterator_base(other) {
}
friend class const_iterator;
};
class const_iterator : public const_iterator_base {
public:
using const_iterator_base::const_iterator_base;
const_iterator(const_iterator_base other) : const_iterator_base(other) {
}
const_iterator(const iterator &other) : const_iterator_base(other._impl) {
}
};
class const_reverse_iterator;
class reverse_iterator : public reverse_iterator_base {
public:
using reverse_iterator_base::reverse_iterator_base;
reverse_iterator(reverse_iterator_base other) : reverse_iterator_base(other) {
}
friend class const_reverse_iterator;
};
class const_reverse_iterator : public const_reverse_iterator_base {
public:
using const_reverse_iterator_base::const_reverse_iterator_base;
const_reverse_iterator(const_reverse_iterator_base other) : const_reverse_iterator_base(other) {
}
const_reverse_iterator(const reverse_iterator &other) : const_reverse_iterator_base(other._impl) {
}
};
using iterator = flat_multi_set_iterator_impl<
Type,
typename impl_t::iterator>;
using const_iterator = flat_multi_set_iterator_impl<
Type,
typename impl_t::const_iterator>;
using reverse_iterator = flat_multi_set_iterator_impl<
Type,
typename impl_t::reverse_iterator>;
using const_reverse_iterator = flat_multi_set_iterator_impl<
Type,
typename impl_t::const_reverse_iterator>;
flat_multi_set() = default;
template <typename Iterator, typename = typename std::iterator_traits<Iterator>::iterator_category>
flat_multi_set(Iterator first, Iterator last) : _impl(first, last) {
std::sort(_impl.begin(), _impl.end());
template <
typename Iterator,
typename = typename std::iterator_traits<Iterator>::iterator_category>
flat_multi_set(Iterator first, Iterator last)
: _data(first, last) {
std::sort(std::begin(impl()), std::end(impl()), compare());
}
flat_multi_set(std::initializer_list<Type> iter)
: flat_multi_set(iter.begin(), iter.end()) {
}
size_type size() const {
return _impl.size();
return impl().size();
}
bool empty() const {
return _impl.empty();
return impl().empty();
}
void clear() {
_impl.clear();
impl().clear();
}
iterator begin() {
return _impl.begin();
return impl().begin();
}
iterator end() {
return _impl.end();
return impl().end();
}
const_iterator begin() const {
return _impl.begin();
return impl().begin();
}
const_iterator end() const {
return _impl.end();
return impl().end();
}
const_iterator cbegin() const {
return _impl.cbegin();
return impl().cbegin();
}
const_iterator cend() const {
return _impl.cend();
return impl().cend();
}
reverse_iterator rbegin() {
return _impl.rbegin();
return impl().rbegin();
}
reverse_iterator rend() {
return _impl.rend();
return impl().rend();
}
const_reverse_iterator rbegin() const {
return _impl.rbegin();
return impl().rbegin();
}
const_reverse_iterator rend() const {
return _impl.rend();
return impl().rend();
}
const_reverse_iterator crbegin() const {
return _impl.crbegin();
return impl().crbegin();
}
const_reverse_iterator crend() const {
return _impl.crend();
return impl().crend();
}
reference front() const {
@@ -244,26 +258,26 @@ public:
}
iterator insert(const Type &value) {
if (empty() || (value < front())) {
_impl.push_front(value);
if (empty() || compare()(value, front())) {
impl().push_front(value);
return begin();
} else if (!(value < back())) {
_impl.push_back(value);
} else if (!compare()(value, back())) {
impl().push_back(value);
return (end() - 1);
}
auto where = getUpperBound(value);
return _impl.insert(where, value);
return impl().insert(where, value);
}
iterator insert(Type &&value) {
if (empty() || (value < front())) {
_impl.push_front(std::move(value));
if (empty() || compare()(value, front())) {
impl().push_front(std::move(value));
return begin();
} else if (!(value < back())) {
_impl.push_back(std::move(value));
} else if (!compare()(value, back())) {
impl().push_back(std::move(value));
return (end() - 1);
}
auto where = getUpperBound(value);
return _impl.insert(where, std::move(value));
return impl().insert(where, std::move(value));
}
template <typename... Args>
iterator emplace(Args&&... args) {
@@ -271,130 +285,354 @@ public:
}
bool removeOne(const Type &value) {
if (empty() || (value < front()) || (back() < value)) {
if (empty()
|| compare()(value, front())
|| compare()(back(), value)) {
return false;
}
auto where = getLowerBound(value);
if (value < *where) {
if (compare()(value, *where)) {
return false;
}
_impl.erase(where);
impl().erase(where);
return true;
}
int removeAll(const Type &value) {
if (empty() || (value < front()) || (back() < value)) {
if (empty()
|| compare()(value, front())
|| compare()(back(), value)) {
return 0;
}
auto range = getEqualRange(value);
if (range.first == range.second) {
return 0;
}
_impl.erase(range.first, range.second);
impl().erase(range.first, range.second);
return (range.second - range.first);
}
iterator erase(iterator where) {
return _impl.erase(where._impl);
iterator erase(const_iterator where) {
return impl().erase(where._impl);
}
iterator erase(iterator from, iterator till) {
return _impl.erase(from._impl, till._impl);
iterator erase(const_iterator from, const_iterator till) {
return impl().erase(from._impl, till._impl);
}
iterator findFirst(const Type &value) {
if (empty() || (value < front()) || (back() < value)) {
if (empty()
|| compare()(value, front())
|| compare()(back(), value)) {
return end();
}
auto where = getLowerBound(value);
return (value < *where) ? _impl.end() : where;
return compare()(value, *where) ? impl().end() : where;
}
const_iterator findFirst(const Type &value) const {
if (empty() || (value < front()) || (back() < value)) {
if (empty()
|| compare()(value, front())
|| compare()(back(), value)) {
return end();
}
auto where = getLowerBound(value);
return (value < *where) ? _impl.end() : where;
return compare()(value, *where) ? impl().end() : where;
}
template <
typename OtherType,
typename = typename Compare::is_transparent>
iterator findFirst(const OtherType &value) {
if (empty()
|| compare()(value, front())
|| compare()(back(), value)) {
return end();
}
auto where = getLowerBound(value);
return compare()(value, *where) ? impl().end() : where;
}
template <
typename OtherType,
typename = typename Compare::is_transparent>
const_iterator findFirst(const OtherType &value) const {
if (empty()
|| compare()(value, front())
|| compare()(back(), value)) {
return end();
}
auto where = getLowerBound(value);
return compare()(value, *where) ? impl().end() : where;
}
bool contains(const Type &value) const {
return findFirst(value) != end();
}
int count(const Type &value) const {
if (empty() || (value < front()) || (back() < value)) {
if (empty()
|| compare()(value, front())
|| compare()(back(), value)) {
return 0;
}
auto range = getEqualRange(value);
return (range.second - range.first);
}
private:
impl _impl;
friend class flat_set<Type>;
template <typename Action>
auto modify(iterator which, Action action) {
auto result = action(which.wrapped());
for (auto i = which + 1, e = end(); i != e; ++i) {
if (compare()(*i, *which)) {
std::swap(i.wrapped(), which.wrapped());
} else {
break;
}
}
for (auto i = which, b = begin(); i != b;) {
--i;
if (compare()(*which, *i)) {
std::swap(i.wrapped(), which.wrapped());
} else {
break;
}
}
return result;
}
typename impl::iterator getLowerBound(const Type &value) {
return std::lower_bound(_impl.begin(), _impl.end(), value);
template <
typename Iterator,
typename = typename std::iterator_traits<Iterator>::iterator_category>
void merge(Iterator first, Iterator last) {
impl().insert(impl().end(), first, last);
std::sort(std::begin(impl()), std::end(impl()), compare());
}
typename impl::const_iterator getLowerBound(const Type &value) const {
return std::lower_bound(_impl.begin(), _impl.end(), value);
void merge(const flat_multi_set<Type, Compare> &other) {
merge(other.begin(), other.end());
}
typename impl::iterator getUpperBound(const Type &value) {
return std::upper_bound(_impl.begin(), _impl.end(), value);
void merge(std::initializer_list<Type> list) {
merge(list.begin(), list.end());
}
typename impl::const_iterator getUpperBound(const Type &value) const {
return std::upper_bound(_impl.begin(), _impl.end(), value);
private:
friend class flat_set<Type, Compare>;
struct transparent_compare : Compare {
inline constexpr const Compare &initial() const noexcept {
return *this;
}
template <
typename OtherType1,
typename OtherType2,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType1>, const_wrap> &&
!std::is_same_v<std::decay_t<OtherType2>, const_wrap>>>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const {
return initial()(
std::forward<OtherType1>(a),
std::forward<OtherType2>(b));
}
template <
typename OtherType1,
typename OtherType2>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const -> std::enable_if_t<
std::is_same_v<std::decay_t<OtherType1>, const_wrap> &&
std::is_same_v<std::decay_t<OtherType2>, const_wrap>, bool> {
return initial()(
static_cast<const Type&>(a),
static_cast<const Type&>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, const_wrap>>>
inline constexpr auto operator()(
const const_wrap &a,
OtherType &&b) const {
return initial()(
static_cast<const Type&>(a),
std::forward<OtherType>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, const_wrap>>>
inline constexpr auto operator()(
OtherType &&a,
const const_wrap &b) const {
return initial()(
std::forward<OtherType>(a),
static_cast<const Type&>(b));
}
};
struct Data : transparent_compare {
template <typename ...Args>
Data(Args &&...args)
: elements(std::forward<Args>(args)...) {
}
impl_t elements;
};
Data _data;
const transparent_compare &compare() const {
return _data;
}
std::pair<typename impl::iterator, typename impl::iterator> getEqualRange(const Type &value) {
return std::equal_range(_impl.begin(), _impl.end(), value);
const impl_t &impl() const {
return _data.elements;
}
std::pair<typename impl::const_iterator, typename impl::const_iterator> getEqualRange(const Type &value) const {
return std::equal_range(_impl.begin(), _impl.end(), value);
impl_t &impl() {
return _data.elements;
}
typename impl_t::iterator getLowerBound(const Type &value) {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
}
typename impl_t::const_iterator getLowerBound(const Type &value) const {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
}
template <
typename OtherType,
typename = typename Compare::is_transparent>
typename impl_t::iterator getLowerBound(const OtherType &value) {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
}
template <
typename OtherType,
typename = typename Compare::is_transparent>
typename impl_t::const_iterator getLowerBound(const OtherType &value) const {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
}
typename impl_t::iterator getUpperBound(const Type &value) {
return std::upper_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
}
typename impl_t::const_iterator getUpperBound(const Type &value) const {
return std::upper_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
}
std::pair<
typename impl_t::iterator,
typename impl_t::iterator
> getEqualRange(const Type &value) {
return std::equal_range(
std::begin(impl()),
std::end(impl()),
value,
compare());
}
std::pair<
typename impl_t::const_iterator,
typename impl_t::const_iterator
> getEqualRange(const Type &value) const {
return std::equal_range(
std::begin(impl()),
std::end(impl()),
value,
compare());
}
};
template <typename Type>
class flat_set : public flat_multi_set<Type> {
using parent = flat_multi_set<Type>;
template <typename Type, typename Compare>
class flat_set : private flat_multi_set<Type, Compare> {
using parent = flat_multi_set<Type, Compare>;
public:
using parent::parent;
using iterator = typename parent::iterator;
using const_iterator = typename parent::const_iterator;
using reverse_iterator = typename parent::reverse_iterator;
using const_reverse_iterator = typename parent::const_reverse_iterator;
using value_type = typename parent::value_type;
using size_type = typename parent::size_type;
using difference_type = typename parent::difference_type;
using pointer = typename parent::pointer;
using reference = typename parent::reference;
flat_set() = default;
template <typename Iterator, typename = typename std::iterator_traits<Iterator>::iterator_category>
template <
typename Iterator,
typename = typename std::iterator_traits<Iterator>::iterator_category
>
flat_set(Iterator first, Iterator last) : parent(first, last) {
this->_impl.erase(std::unique(this->_impl.begin(), this->_impl.end(), [](auto &&a, auto &&b) {
return !(a < b);
}), this->_impl.end());
finalize();
}
flat_set(std::initializer_list<Type> iter) : parent(iter.begin(), iter.end()) {
finalize();
}
using parent::parent;
using parent::size;
using parent::empty;
using parent::clear;
using parent::begin;
using parent::end;
using parent::cbegin;
using parent::cend;
using parent::rbegin;
using parent::rend;
using parent::crbegin;
using parent::crend;
using parent::front;
using parent::back;
using parent::contains;
using parent::erase;
iterator insert(const Type &value) {
if (this->empty() || (value < this->front())) {
this->_impl.push_front(value);
if (this->empty() || this->compare()(value, this->front())) {
this->impl().push_front(value);
return this->begin();
} else if (this->back() < value) {
this->_impl.push_back(value);
} else if (this->compare()(this->back(), value)) {
this->impl().push_back(value);
return (this->end() - 1);
}
auto where = this->getLowerBound(value);
if (value < *where) {
return this->_impl.insert(where, value);
if (this->compare()(value, *where)) {
return this->impl().insert(where, value);
}
return this->end();
}
iterator insert(Type &&value) {
if (this->empty() || (value < this->front())) {
this->_impl.push_front(std::move(value));
if (this->empty() || this->compare()(value, this->front())) {
this->impl().push_front(std::move(value));
return this->begin();
} else if (this->back() < value) {
this->_impl.push_back(std::move(value));
} else if (this->compare()(this->back(), value)) {
this->impl().push_back(std::move(value));
return (this->end() - 1);
}
auto where = this->getLowerBound(value);
if (value < *where) {
return this->_impl.insert(where, std::move(value));
if (this->compare()(value, *where)) {
return this->impl().insert(where, std::move(value));
}
return this->end();
}
@@ -413,6 +651,73 @@ public:
const_iterator find(const Type &value) const {
return this->findFirst(value);
}
template <
typename OtherType,
typename = typename Compare::is_transparent>
iterator find(const OtherType &value) {
return this->findFirst(value);
}
template <
typename OtherType,
typename = typename Compare::is_transparent>
const_iterator find(const OtherType &value) const {
return this->findFirst(value);
}
template <typename Action>
void modify(iterator which, Action action) {
action(which.wrapped());
for (auto i = iterator(which + 1), e = end(); i != e; ++i) {
if (this->compare()(*i, *which)) {
std::swap(i.wrapped(), which.wrapped());
} else if (!this->compare()(*which, *i)) {
erase(which);
return;
} else{
break;
}
}
for (auto i = which, b = begin(); i != b;) {
--i;
if (this->compare()(*which, *i)) {
std::swap(i.wrapped(), which.wrapped());
} else if (!this->compare()(*i, *which)) {
erase(which);
return;
} else {
break;
}
}
}
template <
typename Iterator,
typename = typename std::iterator_traits<Iterator>::iterator_category>
void merge(Iterator first, Iterator last) {
parent::merge(first, last);
finalize();
}
void merge(const flat_multi_set<Type, Compare> &other) {
merge(other.begin(), other.end());
}
void merge(std::initializer_list<Type> list) {
merge(list.begin(), list.end());
}
private:
void finalize() {
this->impl().erase(
std::unique(
std::begin(this->impl()),
std::end(this->impl()),
[&](auto &&a, auto &&b) {
return !this->compare()(a, b);
}
),
std::end(this->impl()));
}
};

View File

@@ -22,13 +22,35 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "base/flat_set.h"
struct int_wrap {
int value;
};
struct int_wrap_comparator {
using is_transparent = void;
inline bool operator()(const int &a, const int_wrap &b) const {
return a < b.value;
}
inline bool operator()(const int_wrap &a, const int_wrap &b) const {
return a.value < b.value;
}
inline bool operator()(const int_wrap &a, const int &b) const {
return a.value < b;
}
inline bool operator()(const int &a, const int &b) const {
return a < b;
}
};
TEST_CASE("flat_sets should keep items sorted", "[flat_set]") {
base::flat_set<int> v;
v.insert(0);
v.insert(5);
v.insert(4);
v.insert(2);
REQUIRE(v.contains(4));
auto checkSorted = [&] {
auto prev = v.begin();
REQUIRE(prev != v.end());
@@ -46,3 +68,30 @@ TEST_CASE("flat_sets should keep items sorted", "[flat_set]") {
checkSorted();
}
}
TEST_CASE("flat_sets with custom comparators", "[flat_set]") {
base::flat_set<int_wrap, int_wrap_comparator> v;
v.insert({ 0 });
v.insert({ 5 });
v.insert({ 4 });
v.insert({ 2 });
REQUIRE(v.find(4) != v.end());
auto checkSorted = [&] {
auto prev = v.begin();
REQUIRE(prev != v.end());
for (auto i = prev + 1; i != v.end(); prev = i, ++i) {
REQUIRE(prev->value < i->value);
}
};
REQUIRE(v.size() == 4);
checkSorted();
SECTION("adding item puts it in the right position") {
v.insert({ 3 });
REQUIRE(v.size() == 5);
REQUIRE(v.find(3) != v.end());
checkSorted();
}
}

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