diff --git a/.gitmodules b/.gitmodules
index fd43d345f..333aa6d9e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -3,7 +3,7 @@
url = https://github.com/telegramdesktop/libtgvoip
[submodule "Telegram/ThirdParty/GSL"]
path = Telegram/ThirdParty/GSL
- url = https://github.com/Microsoft/GSL.git
+ url = https://github.com/desktop-app/GSL.git
[submodule "Telegram/ThirdParty/xxHash"]
path = Telegram/ThirdParty/xxHash
url = https://github.com/Cyan4973/xxHash.git
diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index a4b102499..0042cc86e 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -392,6 +392,7 @@ PRIVATE
calls/calls_video_bubble.h
calls/calls_video_incoming.cpp
calls/calls_video_incoming.h
+ chat_helpers/compose/compose_features.h
chat_helpers/compose/compose_show.cpp
chat_helpers/compose/compose_show.h
chat_helpers/bot_command.cpp
@@ -592,6 +593,12 @@ PRIVATE
data/data_sparse_ids.h
data/data_sponsored_messages.cpp
data/data_sponsored_messages.h
+ data/data_stories.cpp
+ data/data_stories.h
+ data/data_stories_ids.cpp
+ data/data_stories_ids.h
+ data/data_story.cpp
+ data/data_story.h
data/data_streaming.cpp
data/data_streaming.h
data/data_thread.cpp
@@ -632,6 +639,8 @@ PRIVATE
dialogs/ui/dialogs_layout.h
dialogs/ui/dialogs_message_view.cpp
dialogs/ui/dialogs_message_view.h
+ dialogs/ui/dialogs_stories_content.cpp
+ dialogs/ui/dialogs_stories_content.h
dialogs/ui/dialogs_topics_view.cpp
dialogs/ui/dialogs_topics_view.h
dialogs/ui/dialogs_video_userpic.cpp
@@ -735,6 +744,8 @@ PRIVATE
history/view/media/history_view_sticker_player.cpp
history/view/media/history_view_sticker_player.h
history/view/media/history_view_sticker_player_abstract.h
+ history/view/media/history_view_story_mention.cpp
+ history/view/media/history_view_story_mention.h
history/view/media/history_view_theme_document.cpp
history/view/media/history_view_theme_document.h
history/view/media/history_view_userpic_suggestion.cpp
@@ -910,6 +921,12 @@ PRIVATE
info/profile/info_profile_widget.h
info/settings/info_settings_widget.cpp
info/settings/info_settings_widget.h
+ info/stories/info_stories_inner_widget.cpp
+ info/stories/info_stories_inner_widget.h
+ info/stories/info_stories_provider.cpp
+ info/stories/info_stories_provider.h
+ info/stories/info_stories_widget.cpp
+ info/stories/info_stories_widget.h
info/userpic/info_userpic_colors_editor.cpp
info/userpic/info_userpic_colors_editor.h
info/userpic/info_userpic_emoji_builder.cpp
@@ -980,8 +997,6 @@ PRIVATE
main/session/send_as_peers.h
main/session/session_show.cpp
main/session/session_show.h
- media/system_media_controls_manager.h
- media/system_media_controls_manager.cpp
media/audio/media_audio.cpp
media/audio/media_audio.h
media/audio/media_audio_capture.cpp
@@ -1006,6 +1021,28 @@ PRIVATE
media/player/media_player_volume_controller.h
media/player/media_player_widget.cpp
media/player/media_player_widget.h
+ media/stories/media_stories_caption_full_view.cpp
+ media/stories/media_stories_caption_full_view.h
+ media/stories/media_stories_controller.cpp
+ media/stories/media_stories_controller.h
+ media/stories/media_stories_delegate.cpp
+ media/stories/media_stories_delegate.h
+ media/stories/media_stories_header.cpp
+ media/stories/media_stories_header.h
+ media/stories/media_stories_reactions.cpp
+ media/stories/media_stories_reactions.h
+ media/stories/media_stories_recent_views.cpp
+ media/stories/media_stories_recent_views.h
+ media/stories/media_stories_reply.cpp
+ media/stories/media_stories_reply.h
+ media/stories/media_stories_share.cpp
+ media/stories/media_stories_share.h
+ media/stories/media_stories_sibling.cpp
+ media/stories/media_stories_sibling.h
+ media/stories/media_stories_slider.cpp
+ media/stories/media_stories_slider.h
+ media/stories/media_stories_view.cpp
+ media/stories/media_stories_view.h
media/streaming/media_streaming_audio_track.cpp
media/streaming/media_streaming_audio_track.h
media/streaming/media_streaming_common.h
@@ -1051,6 +1088,8 @@ PRIVATE
media/view/media_view_playback_progress.cpp
media/view/media_view_playback_progress.h
media/view/media_view_open_common.h
+ media/system_media_controls_manager.h
+ media/system_media_controls_manager.cpp
menu/menu_antispam_validator.cpp
menu/menu_antispam_validator.h
menu/menu_item_download_files.cpp
diff --git a/Telegram/Resources/export_html/css/style.css b/Telegram/Resources/export_html/css/style.css
index 456d59f46..79b680cc2 100644
--- a/Telegram/Resources/export_html/css/style.css
+++ b/Telegram/Resources/export_html/css/style.css
@@ -111,6 +111,11 @@ pre {
border-radius: 50%;
overflow: hidden;
}
+.story {
+ display: block;
+ border-radius: 4px;
+ overflow: hidden;
+}
.userpic .initials {
display: block;
color: #fff;
@@ -194,6 +199,10 @@ a.block_link:hover {
text-decoration: none !important;
background-color: #f5f7f8;
}
+a.expanded {
+ padding: 2px 8px;
+ margin: -2px -8px;
+}
.sections {
padding: 11px 0;
}
@@ -428,6 +437,9 @@ div.toast_shown {
.section.sessions {
background-image: url(../images/section_sessions.png);
}
+.section.stories {
+ background-image: url(../images/section_stories.png);
+}
.section.web {
background-image: url(../images/section_web.png);
}
@@ -489,6 +501,9 @@ div.toast_shown {
.section.sessions {
background-image: url(../images/section_sessions@2x.png);
}
+.section.stories {
+ background-image: url(../images/section_stories@2x.png);
+}
.section.web {
background-image: url(../images/section_web@2x.png);
}
diff --git a/Telegram/Resources/export_html/images/section_stories.png b/Telegram/Resources/export_html/images/section_stories.png
new file mode 100644
index 000000000..650c69c91
Binary files /dev/null and b/Telegram/Resources/export_html/images/section_stories.png differ
diff --git a/Telegram/Resources/export_html/images/section_stories@2x.png b/Telegram/Resources/export_html/images/section_stories@2x.png
new file mode 100644
index 000000000..429245138
Binary files /dev/null and b/Telegram/Resources/export_html/images/section_stories@2x.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_lock.png b/Telegram/Resources/icons/dialogs/dialogs_lock.png
deleted file mode 100644
index cd953f753..000000000
Binary files a/Telegram/Resources/icons/dialogs/dialogs_lock.png and /dev/null differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_lock@2x.png b/Telegram/Resources/icons/dialogs/dialogs_lock@2x.png
deleted file mode 100644
index d29e0579f..000000000
Binary files a/Telegram/Resources/icons/dialogs/dialogs_lock@2x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_lock@3x.png b/Telegram/Resources/icons/dialogs/dialogs_lock@3x.png
deleted file mode 100644
index 796427920..000000000
Binary files a/Telegram/Resources/icons/dialogs/dialogs_lock@3x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_lock_off.png b/Telegram/Resources/icons/dialogs/dialogs_lock_off.png
new file mode 100644
index 000000000..2459e1137
Binary files /dev/null and b/Telegram/Resources/icons/dialogs/dialogs_lock_off.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_lock_off@2x.png b/Telegram/Resources/icons/dialogs/dialogs_lock_off@2x.png
new file mode 100644
index 000000000..33b77eb3f
Binary files /dev/null and b/Telegram/Resources/icons/dialogs/dialogs_lock_off@2x.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_lock_off@3x.png b/Telegram/Resources/icons/dialogs/dialogs_lock_off@3x.png
new file mode 100644
index 000000000..7653aa431
Binary files /dev/null and b/Telegram/Resources/icons/dialogs/dialogs_lock_off@3x.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_lock_on.png b/Telegram/Resources/icons/dialogs/dialogs_lock_on.png
new file mode 100644
index 000000000..8209991f3
Binary files /dev/null and b/Telegram/Resources/icons/dialogs/dialogs_lock_on.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_lock_on@2x.png b/Telegram/Resources/icons/dialogs/dialogs_lock_on@2x.png
new file mode 100644
index 000000000..c4e3d6b25
Binary files /dev/null and b/Telegram/Resources/icons/dialogs/dialogs_lock_on@2x.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_lock_on@3x.png b/Telegram/Resources/icons/dialogs/dialogs_lock_on@3x.png
new file mode 100644
index 000000000..67c7d7c71
Binary files /dev/null and b/Telegram/Resources/icons/dialogs/dialogs_lock_on@3x.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_unlock.png b/Telegram/Resources/icons/dialogs/dialogs_unlock.png
deleted file mode 100644
index 207f93bb9..000000000
Binary files a/Telegram/Resources/icons/dialogs/dialogs_unlock.png and /dev/null differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_unlock@2x.png b/Telegram/Resources/icons/dialogs/dialogs_unlock@2x.png
deleted file mode 100644
index 64359ff67..000000000
Binary files a/Telegram/Resources/icons/dialogs/dialogs_unlock@2x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_unlock@3x.png b/Telegram/Resources/icons/dialogs/dialogs_unlock@3x.png
deleted file mode 100644
index c62942302..000000000
Binary files a/Telegram/Resources/icons/dialogs/dialogs_unlock@3x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/emoji/stickers_add.png b/Telegram/Resources/icons/emoji/stickers_add.png
deleted file mode 100644
index d4c77a202..000000000
Binary files a/Telegram/Resources/icons/emoji/stickers_add.png and /dev/null differ
diff --git a/Telegram/Resources/icons/emoji/stickers_add@2x.png b/Telegram/Resources/icons/emoji/stickers_add@2x.png
deleted file mode 100644
index f188f440d..000000000
Binary files a/Telegram/Resources/icons/emoji/stickers_add@2x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/emoji/stickers_add@3x.png b/Telegram/Resources/icons/emoji/stickers_add@3x.png
deleted file mode 100644
index 48de8115e..000000000
Binary files a/Telegram/Resources/icons/emoji/stickers_add@3x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot.png b/Telegram/Resources/icons/emoji/stickers_add_dot.png
deleted file mode 100644
index 1bb4078f4..000000000
Binary files a/Telegram/Resources/icons/emoji/stickers_add_dot.png and /dev/null differ
diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png b/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png
deleted file mode 100644
index 1723a7f36..000000000
Binary files a/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png b/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png
deleted file mode 100644
index ce7f1aa76..000000000
Binary files a/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread.png b/Telegram/Resources/icons/emoji/stickers_add_unread.png
deleted file mode 100644
index d8172e22b..000000000
Binary files a/Telegram/Resources/icons/emoji/stickers_add_unread.png and /dev/null differ
diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png b/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png
deleted file mode 100644
index c48562529..000000000
Binary files a/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png b/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png
deleted file mode 100644
index 46a03b994..000000000
Binary files a/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/info/info_media_stories.png b/Telegram/Resources/icons/info/info_media_stories.png
new file mode 100644
index 000000000..5b4cb99be
Binary files /dev/null and b/Telegram/Resources/icons/info/info_media_stories.png differ
diff --git a/Telegram/Resources/icons/info/info_media_stories@2x.png b/Telegram/Resources/icons/info/info_media_stories@2x.png
new file mode 100644
index 000000000..fc0a2f6e3
Binary files /dev/null and b/Telegram/Resources/icons/info/info_media_stories@2x.png differ
diff --git a/Telegram/Resources/icons/info/info_media_stories@3x.png b/Telegram/Resources/icons/info/info_media_stories@3x.png
new file mode 100644
index 000000000..df8a23bbd
Binary files /dev/null and b/Telegram/Resources/icons/info/info_media_stories@3x.png differ
diff --git a/Telegram/Resources/icons/info/info_media_story_empty.png b/Telegram/Resources/icons/info/info_media_story_empty.png
new file mode 100644
index 000000000..6196956ba
Binary files /dev/null and b/Telegram/Resources/icons/info/info_media_story_empty.png differ
diff --git a/Telegram/Resources/icons/info/info_media_story_empty@2x.png b/Telegram/Resources/icons/info/info_media_story_empty@2x.png
new file mode 100644
index 000000000..c3e6997cd
Binary files /dev/null and b/Telegram/Resources/icons/info/info_media_story_empty@2x.png differ
diff --git a/Telegram/Resources/icons/info/info_media_story_empty@3x.png b/Telegram/Resources/icons/info/info_media_story_empty@3x.png
new file mode 100644
index 000000000..b6422809d
Binary files /dev/null and b/Telegram/Resources/icons/info/info_media_story_empty@3x.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_archive.png b/Telegram/Resources/icons/info/info_stories_archive.png
new file mode 100644
index 000000000..9b4b79ce4
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_archive.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_archive@2x.png b/Telegram/Resources/icons/info/info_stories_archive@2x.png
new file mode 100644
index 000000000..831363fa5
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_archive@2x.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_archive@3x.png b/Telegram/Resources/icons/info/info_stories_archive@3x.png
new file mode 100644
index 000000000..e02e85c6c
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_archive@3x.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_recent.png b/Telegram/Resources/icons/info/info_stories_recent.png
new file mode 100644
index 000000000..341ee2a06
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_recent.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_recent@2x.png b/Telegram/Resources/icons/info/info_stories_recent@2x.png
new file mode 100644
index 000000000..ecb3fc72d
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_recent@2x.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_recent@3x.png b/Telegram/Resources/icons/info/info_stories_recent@3x.png
new file mode 100644
index 000000000..bacf1a3c1
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_recent@3x.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_to_archive.png b/Telegram/Resources/icons/info/info_stories_to_archive.png
new file mode 100644
index 000000000..f9c81896e
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_to_archive.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_to_archive@2x.png b/Telegram/Resources/icons/info/info_stories_to_archive@2x.png
new file mode 100644
index 000000000..ef905891c
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_to_archive@2x.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_to_archive@3x.png b/Telegram/Resources/icons/info/info_stories_to_archive@3x.png
new file mode 100644
index 000000000..bc2fc30af
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_to_archive@3x.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_to_profile.png b/Telegram/Resources/icons/info/info_stories_to_profile.png
new file mode 100644
index 000000000..cfe465c5b
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_to_profile.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_to_profile@2x.png b/Telegram/Resources/icons/info/info_stories_to_profile@2x.png
new file mode 100644
index 000000000..1e9990c2f
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_to_profile@2x.png differ
diff --git a/Telegram/Resources/icons/info/info_stories_to_profile@3x.png b/Telegram/Resources/icons/info/info_stories_to_profile@3x.png
new file mode 100644
index 000000000..414fa60a2
Binary files /dev/null and b/Telegram/Resources/icons/info/info_stories_to_profile@3x.png differ
diff --git a/Telegram/Resources/icons/mediaview/mini_close_friends.png b/Telegram/Resources/icons/mediaview/mini_close_friends.png
new file mode 100644
index 000000000..5c3072447
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_close_friends.png differ
diff --git a/Telegram/Resources/icons/mediaview/mini_close_friends@2x.png b/Telegram/Resources/icons/mediaview/mini_close_friends@2x.png
new file mode 100644
index 000000000..82dd44af9
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_close_friends@2x.png differ
diff --git a/Telegram/Resources/icons/mediaview/mini_close_friends@3x.png b/Telegram/Resources/icons/mediaview/mini_close_friends@3x.png
new file mode 100644
index 000000000..1f024ce73
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_close_friends@3x.png differ
diff --git a/Telegram/Resources/icons/mediaview/mini_contacts.png b/Telegram/Resources/icons/mediaview/mini_contacts.png
new file mode 100644
index 000000000..bc716cab4
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_contacts.png differ
diff --git a/Telegram/Resources/icons/mediaview/mini_contacts@2x.png b/Telegram/Resources/icons/mediaview/mini_contacts@2x.png
new file mode 100644
index 000000000..a7df593e8
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_contacts@2x.png differ
diff --git a/Telegram/Resources/icons/mediaview/mini_contacts@3x.png b/Telegram/Resources/icons/mediaview/mini_contacts@3x.png
new file mode 100644
index 000000000..50c9ff55f
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_contacts@3x.png differ
diff --git a/Telegram/Resources/icons/mediaview/mini_selected_contacts.png b/Telegram/Resources/icons/mediaview/mini_selected_contacts.png
new file mode 100644
index 000000000..c3ca5b06d
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_selected_contacts.png differ
diff --git a/Telegram/Resources/icons/mediaview/mini_selected_contacts@2x.png b/Telegram/Resources/icons/mediaview/mini_selected_contacts@2x.png
new file mode 100644
index 000000000..d12f95496
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_selected_contacts@2x.png differ
diff --git a/Telegram/Resources/icons/mediaview/mini_selected_contacts@3x.png b/Telegram/Resources/icons/mediaview/mini_selected_contacts@3x.png
new file mode 100644
index 000000000..90860348b
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_selected_contacts@3x.png differ
diff --git a/Telegram/Resources/icons/mediaview/stories_next.png b/Telegram/Resources/icons/mediaview/stories_next.png
new file mode 100644
index 000000000..dd997b2d0
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/stories_next.png differ
diff --git a/Telegram/Resources/icons/mediaview/stories_next@2x.png b/Telegram/Resources/icons/mediaview/stories_next@2x.png
new file mode 100644
index 000000000..82b819e9e
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/stories_next@2x.png differ
diff --git a/Telegram/Resources/icons/mediaview/stories_next@3x.png b/Telegram/Resources/icons/mediaview/stories_next@3x.png
new file mode 100644
index 000000000..3550c8cce
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/stories_next@3x.png differ
diff --git a/Telegram/Resources/icons/mediaview/viewer_share.png b/Telegram/Resources/icons/mediaview/viewer_share.png
new file mode 100644
index 000000000..14861b1ee
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/viewer_share.png differ
diff --git a/Telegram/Resources/icons/mediaview/viewer_share@2x.png b/Telegram/Resources/icons/mediaview/viewer_share@2x.png
new file mode 100644
index 000000000..7c6e9341e
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/viewer_share@2x.png differ
diff --git a/Telegram/Resources/icons/mediaview/viewer_share@3x.png b/Telegram/Resources/icons/mediaview/viewer_share@3x.png
new file mode 100644
index 000000000..43310c895
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/viewer_share@3x.png differ
diff --git a/Telegram/Resources/icons/menu/archive_open.png b/Telegram/Resources/icons/menu/archive_open.png
new file mode 100644
index 000000000..2e3090130
Binary files /dev/null and b/Telegram/Resources/icons/menu/archive_open.png differ
diff --git a/Telegram/Resources/icons/menu/archive_open@2x.png b/Telegram/Resources/icons/menu/archive_open@2x.png
new file mode 100644
index 000000000..c95bd9f66
Binary files /dev/null and b/Telegram/Resources/icons/menu/archive_open@2x.png differ
diff --git a/Telegram/Resources/icons/menu/archive_open@3x.png b/Telegram/Resources/icons/menu/archive_open@3x.png
new file mode 100644
index 000000000..74687f9ec
Binary files /dev/null and b/Telegram/Resources/icons/menu/archive_open@3x.png differ
diff --git a/Telegram/Resources/icons/menu/channel.png b/Telegram/Resources/icons/menu/channel.png
index df2823788..d6caf7131 100644
Binary files a/Telegram/Resources/icons/menu/channel.png and b/Telegram/Resources/icons/menu/channel.png differ
diff --git a/Telegram/Resources/icons/menu/channel@2x.png b/Telegram/Resources/icons/menu/channel@2x.png
index 68e65eade..c68e6a6b0 100644
Binary files a/Telegram/Resources/icons/menu/channel@2x.png and b/Telegram/Resources/icons/menu/channel@2x.png differ
diff --git a/Telegram/Resources/icons/menu/channel@3x.png b/Telegram/Resources/icons/menu/channel@3x.png
index e3f8e50d3..0ce3d46a9 100644
Binary files a/Telegram/Resources/icons/menu/channel@3x.png and b/Telegram/Resources/icons/menu/channel@3x.png differ
diff --git a/Telegram/Resources/icons/menu/groups.png b/Telegram/Resources/icons/menu/groups.png
new file mode 100644
index 000000000..2fc454a36
Binary files /dev/null and b/Telegram/Resources/icons/menu/groups.png differ
diff --git a/Telegram/Resources/icons/menu/groups@2x.png b/Telegram/Resources/icons/menu/groups@2x.png
new file mode 100644
index 000000000..986bc696d
Binary files /dev/null and b/Telegram/Resources/icons/menu/groups@2x.png differ
diff --git a/Telegram/Resources/icons/menu/groups@3x.png b/Telegram/Resources/icons/menu/groups@3x.png
new file mode 100644
index 000000000..28ed4085f
Binary files /dev/null and b/Telegram/Resources/icons/menu/groups@3x.png differ
diff --git a/Telegram/Resources/icons/menu/night_mode.png b/Telegram/Resources/icons/menu/night_mode.png
new file mode 100644
index 000000000..531195e73
Binary files /dev/null and b/Telegram/Resources/icons/menu/night_mode.png differ
diff --git a/Telegram/Resources/icons/menu/night_mode@2x.png b/Telegram/Resources/icons/menu/night_mode@2x.png
new file mode 100644
index 000000000..1742270a3
Binary files /dev/null and b/Telegram/Resources/icons/menu/night_mode@2x.png differ
diff --git a/Telegram/Resources/icons/menu/night_mode@3x.png b/Telegram/Resources/icons/menu/night_mode@3x.png
new file mode 100644
index 000000000..601217161
Binary files /dev/null and b/Telegram/Resources/icons/menu/night_mode@3x.png differ
diff --git a/Telegram/Resources/icons/menu/profile.png b/Telegram/Resources/icons/menu/profile.png
index 962419484..99861b419 100644
Binary files a/Telegram/Resources/icons/menu/profile.png and b/Telegram/Resources/icons/menu/profile.png differ
diff --git a/Telegram/Resources/icons/menu/profile@2x.png b/Telegram/Resources/icons/menu/profile@2x.png
index fe742a412..14faac768 100644
Binary files a/Telegram/Resources/icons/menu/profile@2x.png and b/Telegram/Resources/icons/menu/profile@2x.png differ
diff --git a/Telegram/Resources/icons/menu/profile@3x.png b/Telegram/Resources/icons/menu/profile@3x.png
index e2cf03667..f760db92b 100644
Binary files a/Telegram/Resources/icons/menu/profile@3x.png and b/Telegram/Resources/icons/menu/profile@3x.png differ
diff --git a/Telegram/Resources/icons/menu/saved_messages.png b/Telegram/Resources/icons/menu/saved_messages.png
new file mode 100644
index 000000000..3b8ba1eb7
Binary files /dev/null and b/Telegram/Resources/icons/menu/saved_messages.png differ
diff --git a/Telegram/Resources/icons/menu/saved_messages@2x.png b/Telegram/Resources/icons/menu/saved_messages@2x.png
new file mode 100644
index 000000000..b89a09231
Binary files /dev/null and b/Telegram/Resources/icons/menu/saved_messages@2x.png differ
diff --git a/Telegram/Resources/icons/menu/saved_messages@3x.png b/Telegram/Resources/icons/menu/saved_messages@3x.png
new file mode 100644
index 000000000..6fa7627de
Binary files /dev/null and b/Telegram/Resources/icons/menu/saved_messages@3x.png differ
diff --git a/Telegram/Resources/icons/menu/settings.png b/Telegram/Resources/icons/menu/settings.png
index 4453866e9..27b0cbcd6 100644
Binary files a/Telegram/Resources/icons/menu/settings.png and b/Telegram/Resources/icons/menu/settings.png differ
diff --git a/Telegram/Resources/icons/menu/settings@2x.png b/Telegram/Resources/icons/menu/settings@2x.png
index e255fb46a..76e0fbbe4 100644
Binary files a/Telegram/Resources/icons/menu/settings@2x.png and b/Telegram/Resources/icons/menu/settings@2x.png differ
diff --git a/Telegram/Resources/icons/menu/settings@3x.png b/Telegram/Resources/icons/menu/settings@3x.png
index 79b2cf6d2..5135a603e 100644
Binary files a/Telegram/Resources/icons/menu/settings@3x.png and b/Telegram/Resources/icons/menu/settings@3x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_archive.png b/Telegram/Resources/icons/menu/stories_archive.png
new file mode 100644
index 000000000..a98e8583c
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_archive.png differ
diff --git a/Telegram/Resources/icons/menu/stories_archive@2x.png b/Telegram/Resources/icons/menu/stories_archive@2x.png
new file mode 100644
index 000000000..5c5602569
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_archive@2x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_archive@3x.png b/Telegram/Resources/icons/menu/stories_archive@3x.png
new file mode 100644
index 000000000..715f241ba
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_archive@3x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_archive_section.png b/Telegram/Resources/icons/menu/stories_archive_section.png
new file mode 100644
index 000000000..d86b5dc87
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_archive_section.png differ
diff --git a/Telegram/Resources/icons/menu/stories_archive_section@2x.png b/Telegram/Resources/icons/menu/stories_archive_section@2x.png
new file mode 100644
index 000000000..f2c59be33
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_archive_section@2x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_archive_section@3x.png b/Telegram/Resources/icons/menu/stories_archive_section@3x.png
new file mode 100644
index 000000000..f6369c74c
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_archive_section@3x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_save.png b/Telegram/Resources/icons/menu/stories_save.png
new file mode 100644
index 000000000..68d2a12f4
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_save.png differ
diff --git a/Telegram/Resources/icons/menu/stories_save@2x.png b/Telegram/Resources/icons/menu/stories_save@2x.png
new file mode 100644
index 000000000..327054159
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_save@2x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_save@3x.png b/Telegram/Resources/icons/menu/stories_save@3x.png
new file mode 100644
index 000000000..e97dac0ab
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_save@3x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_saved_section.png b/Telegram/Resources/icons/menu/stories_saved_section.png
new file mode 100644
index 000000000..31a29d96b
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_saved_section.png differ
diff --git a/Telegram/Resources/icons/menu/stories_saved_section@2x.png b/Telegram/Resources/icons/menu/stories_saved_section@2x.png
new file mode 100644
index 000000000..02a9f4687
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_saved_section@2x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_saved_section@3x.png b/Telegram/Resources/icons/menu/stories_saved_section@3x.png
new file mode 100644
index 000000000..8de09fb32
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_saved_section@3x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_to_chats.png b/Telegram/Resources/icons/menu/stories_to_chats.png
new file mode 100644
index 000000000..b5129521c
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_to_chats.png differ
diff --git a/Telegram/Resources/icons/menu/stories_to_chats@2x.png b/Telegram/Resources/icons/menu/stories_to_chats@2x.png
new file mode 100644
index 000000000..575fcc811
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_to_chats@2x.png differ
diff --git a/Telegram/Resources/icons/menu/stories_to_chats@3x.png b/Telegram/Resources/icons/menu/stories_to_chats@3x.png
new file mode 100644
index 000000000..00f6b959b
Binary files /dev/null and b/Telegram/Resources/icons/menu/stories_to_chats@3x.png differ
diff --git a/Telegram/Resources/icons/settings/stories.png b/Telegram/Resources/icons/settings/stories.png
new file mode 100644
index 000000000..c41ac06dd
Binary files /dev/null and b/Telegram/Resources/icons/settings/stories.png differ
diff --git a/Telegram/Resources/icons/settings/stories@2x.png b/Telegram/Resources/icons/settings/stories@2x.png
new file mode 100644
index 000000000..82e24fc67
Binary files /dev/null and b/Telegram/Resources/icons/settings/stories@2x.png differ
diff --git a/Telegram/Resources/icons/settings/stories@3x.png b/Telegram/Resources/icons/settings/stories@3x.png
new file mode 100644
index 000000000..23c70a8cc
Binary files /dev/null and b/Telegram/Resources/icons/settings/stories@3x.png differ
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 4b37c2697..5a0e5e847 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_menu_activate" = "Activate";
"lng_menu_set_status" = "Set Emoji Status";
"lng_menu_change_status" = "Change Emoji Status";
+"lng_menu_my_stories" = "My Stories";
"lng_disable_notifications_from_tray" = "Disable notifications";
"lng_enable_notifications_from_tray" = "Enable notifications";
@@ -285,6 +286,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_edit_message_text" = "New message text...";
"lng_deleted" = "Deleted Account";
"lng_deleted_message" = "Deleted message";
+"lng_deleted_story" = "Deleted story";
"lng_pinned_message" = "Pinned message";
"lng_pinned_previous" = "Previous message";
"lng_pinned_unpin_sure" = "Would you like to unpin this message?";
@@ -583,6 +585,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_forwards_privacy" = "Forwarded messages";
"lng_settings_profile_photo_privacy" = "Profile photo";
"lng_settings_voices_privacy" = "Voice messages";
+"lng_settings_bio_privacy" = "Bio";
"lng_settings_privacy_premium" = "Only subscribers of {link} can restrict receiving voice messages.";
"lng_settings_privacy_premium_link" = "Telegram Premium";
"lng_settings_passcode_disable" = "Disable Passcode";
@@ -754,6 +757,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_background_apply2" = "Enjoy the view.";
"lng_background_apply_button" = "Apply For This Chat";
"lng_background_dimming" = "Background dimming";
+"lng_background_sure_reset_default" = "Are you sure you want to reset the wallpaper?";
+"lng_background_reset_default" = "Reset";
"lng_download_path_ask" = "Ask download path for each file";
"lng_download_path" = "Download path";
@@ -961,6 +966,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_edit_privacy_everyone" = "Everybody";
"lng_edit_privacy_contacts" = "My contacts";
+"lng_edit_privacy_close_friends" = "Close friends";
"lng_edit_privacy_nobody" = "Nobody";
"lng_edit_privacy_exceptions" = "Add exceptions";
@@ -997,6 +1003,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_edit_privacy_groups_always_title" = "Always allow";
"lng_edit_privacy_groups_never_title" = "Never allow";
+"lng_edit_privacy_about_title" = "Bio privacy settings";
+"lng_edit_privacy_about_header" = "Who can see my bio";
+"lng_edit_privacy_about_always_empty" = "Always allow";
+"lng_edit_privacy_about_never_empty" = "Never allow";
+"lng_edit_privacy_about_exceptions" = "These users will or will not be able to see your profile bio regardless of the settings above.";
+"lng_edit_privacy_about_always_title" = "Always allow";
+"lng_edit_privacy_about_never_title" = "Never allow";
+
"lng_edit_privacy_calls_title" = "Voice calls privacy";
"lng_edit_privacy_calls_header" = "Who can call you";
"lng_edit_privacy_calls_always_empty" = "Always allow";
@@ -1111,6 +1125,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_sure_kick_channel" = "Remove {user} from the channel?";
"lng_profile_sure_remove_admin" = "Remove {user} from admins?";
"lng_profile_loading" = "Loading...";
+"lng_profile_saved_stories#one" = "{count} saved story";
+"lng_profile_saved_stories#other" = "{count} saved stories";
"lng_profile_photos#one" = "{count} photo";
"lng_profile_photos#other" = "{count} photos";
"lng_profile_gifs#one" = "{count} GIF";
@@ -1334,6 +1350,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_report_group_video_title" = "Report group video";
"lng_report_channel_photo_title" = "Report channel photo";
"lng_report_channel_video_title" = "Report channel video";
+"lng_report_story" = "Report story";
"lng_report_please_select_messages" = "Please select messages to report.";
"lng_report_select_messages" = "Select messages";
"lng_report_messages_none" = "Select Messages";
@@ -1491,6 +1508,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_pinned_media_sticker" = "a sticker";
"lng_action_pinned_media_emoji_sticker" = "a {emoji} sticker";
"lng_action_pinned_media_game" = "the game «{game}»";
+"lng_action_pinned_media_story" = "a story";
"lng_action_game_score#one" = "{from} scored {count} in {game}";
"lng_action_game_score#other" = "{from} scored {count} in {game}";
"lng_action_game_you_scored#one" = "You scored {count} in {game}";
@@ -1556,6 +1574,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_topic_icon_changed" = "{from} changed the {link} icon to {emoji}";
"lng_action_topic_icon_removed" = "{from} removed the {link} icon";
"lng_action_shared_chat_with_bot" = "You shared {chat} with {bot}";
+"lng_action_story_mention_me" = "You mentioned {user} in a story";
+"lng_action_story_mention" = "{user} mentioned you in a story";
+"lng_action_story_mention_button" = "View Story";
+"lng_action_story_mention_me_unavailable" = "The story where you mentioned {user} is no longer available.";
+"lng_action_story_mention_unavailable" = "The story where {user} mentioned you is no longer available.";
"lng_premium_gift_duration_months#one" = "for {count} month";
"lng_premium_gift_duration_months#other" = "for {count} months";
@@ -1686,6 +1709,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_about_private_link" = "This link will only work for members of this chat.";
"lng_forwarded" = "Forwarded from {user}";
+"lng_forwarded_story" = "Story from {user}";
"lng_forwarded_date" = "Original: {date}";
"lng_forwarded_channel" = "Forwarded from {channel}";
"lng_forwarded_psa_default" = "Forwarded from {channel}";
@@ -1960,6 +1984,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_in_dlg_sticker" = "Sticker";
"lng_in_dlg_sticker_emoji" = "{emoji} Sticker";
"lng_in_dlg_poll" = "Poll";
+"lng_in_dlg_story" = "Story";
+"lng_in_dlg_story_expired" = "Expired story";
"lng_in_dlg_media_count#one" = "{count} media";
"lng_in_dlg_media_count#other" = "{count} media";
"lng_in_dlg_photo_count#one" = "{count} photo";
@@ -2018,6 +2044,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_broadcast_ph" = "Broadcast a message...";
"lng_broadcast_silent_ph" = "Silent broadcast...";
"lng_send_anonymous_ph" = "Send anonymously...";
+"lng_story_reply_ph" = "Reply privately...";
"lng_send_text_no" = "Text not allowed.";
"lng_send_text_no_about" = "The admins of this group only allow sending {types}.";
"lng_send_text_type_and_last" = "{types} and {last}";
@@ -2035,6 +2062,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_send_as_premium_required" = "Subscribe to {link} to be able to comment on behalf of your channels in group chats.";
"lng_send_as_premium_required_link" = "Telegram Premium";
"lng_record_cancel" = "Release outside this field to cancel";
+"lng_record_cancel_stories" = "Release outside to cancel";
"lng_record_lock_cancel_sure" = "Are you sure you want to stop recording and discard your voice message?";
"lng_record_listen_cancel_sure" = "Are you sure you want to discard your recorded voice message?";
"lng_record_lock_discard" = "Discard";
@@ -2381,6 +2409,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_add_contact" = "Create";
"lng_add_contact_button" = "New contact";
"lng_contacts_header" = "Contacts";
+"lng_contacts_hidden_stories" = "Hidden Stories";
+"lng_contacts_stories_status#one" = "{count} story";
+"lng_contacts_stories_status#other" = "{count} stories";
+"lng_contacts_stories_status_new#one" = "{count} new story";
+"lng_contacts_stories_status_new#other" = "{count} new stories";
"lng_contact_not_joined" = "Unfortunately {name} has not joined Telegram yet, but you can send them an invitation.\n\nWe will notify you about any of your contacts who join Telegram.";
"lng_try_other_contact" = "Try someone else";
"lng_create_group_link" = "Link";
@@ -2451,6 +2484,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_mediaview_copy" = "Copy";
"lng_mediaview_forward" = "Forward";
"lng_mediaview_delete" = "Delete";
+"lng_mediaview_save_to_profile" = "Save to Profile";
+"lng_mediaview_archive_story" = "Archive Story";
"lng_mediaview_photos_all" = "View all photos";
"lng_mediaview_files_all" = "View all files";
"lng_mediaview_single_photo" = "Single Photo";
@@ -2464,6 +2499,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_mediaview_doc_image" = "File";
"lng_mediaview_today" = "today at {time}";
"lng_mediaview_yesterday" = "yesterday at {time}";
+"lng_mediaview_just_now" = "just now";
+"lng_mediaview_minutes_ago#one" = "{count} minute ago";
+"lng_mediaview_minutes_ago#other" = "{count} minutes ago";
+"lng_mediaview_hours_ago#one" = "{count} hour ago";
+"lng_mediaview_hours_ago#other" = "{count} hours ago";
"lng_mediaview_date_time" = "{date} at {time}";
"lng_mediaview_set_userpic" = "Set as Main";
"lng_mediaview_report_profile_photo" = "Report";
@@ -2471,6 +2511,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_mediaview_title" = "Media viewer";
"lng_mediaview_saved_to" = "Image was saved to your {downloads} folder";
"lng_mediaview_saved_images_to" = "Images were saved to your {downloads} folder";
+"lng_mediaview_video_saved_to" = "Video file was saved to your {downloads} folder";
"lng_mediaview_downloads" = "Downloads";
"lng_mediaview_playback_speed" = "Playback speed: {speed}";
"lng_mediaview_rotate_video" = "Rotate video";
@@ -3389,6 +3430,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_export_option_info_about" = "Your chosen screen name, username, phone number and profile pictures.";
"lng_export_option_contacts" = "Contacts list";
"lng_export_option_contacts_about" = "If you allow access, contacts are continuously synced with Telegram. You can adjust this in Settings > Privacy & Security on mobile devices.";
+"lng_export_option_stories" = "Stories archive";
+"lng_export_option_stories_about" = "All stories you posted from Telegram mobile apps.";
"lng_export_option_sessions" = "Active sessions";
"lng_export_option_sessions_about" = "We store this to display your connected devices in Settings > Privacy & Security > Active Sessions.";
"lng_export_header_other" = "Other";
@@ -3675,9 +3718,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_view_button_background" = "View background";
"lng_view_button_theme" = "View theme";
"lng_view_button_message" = "View message";
+"lng_view_button_story" = "View story";
"lng_view_button_voice_chat" = "Voice chat";
"lng_view_button_voice_chat_channel" = "Live stream";
"lng_view_button_request_join" = "Request to Join";
+"lng_view_button_external_link" = "Open link";
"lng_sponsored_hide_ads" = "Hide";
"lng_sponsored_title" = "What are sponsored messages?";
@@ -3777,6 +3822,44 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_userpic_builder_color_subtitle" = "Choose background";
"lng_userpic_builder_emoji_subtitle" = "Choose sticker or emoji";
+"lng_stories_my_name" = "My Story";
+"lng_stories_archive" = "Hide Stories";
+"lng_stories_unarchive" = "Unhide Stories";
+"lng_stories_row_count#one" = "{count} Story";
+"lng_stories_row_count#other" = "{count} Stories";
+"lng_stories_views#one" = "{count} view";
+"lng_stories_views#other" = "{count} views";
+"lng_stories_no_views" = "No views";
+"lng_stories_unsupported" = "This story is not supported\nby your version of Telegram.";
+"lng_stories_cant_reply" = "You can't reply to this story.";
+
+"lng_stories_my_title" = "Saved Stories";
+"lng_stories_archive_button" = "Stories Archive";
+"lng_stories_recent_button" = "Recent Stories";
+"lng_stories_archive_title" = "Stories Archive";
+"lng_stories_archive_about" = "Only you can see archived stories unless you choose to save them to your profile.";
+"lng_stories_reply_sent" = "Message Sent";
+"lng_stories_hidden_to_contacts" = "Stories from {user} will now be shown in **Archived Chats**.";
+"lng_stories_shown_in_chats" = "Stories from {user} will now be shown in the **Chats List**.";
+"lng_stories_delete_one_sure" = "Are you sure you want to delete this story?";
+"lng_stories_delete_sure#one" = "Are you sure you want to delete {count} story?";
+"lng_stories_delete_sure#other" = "Are you sure you want to delete {count} stories?";
+"lng_stories_save_sure" = "Do you want to save this story to your profile?";
+"lng_stories_save_sure_many#one" = "Do you want to save {count} story to your profile?";
+"lng_stories_save_sure_many#other" = "Do you want to save {count} stories to your profile?";
+"lng_stories_save_done" = "This story is saved to your profile.";
+"lng_stories_save_done_many#one" = "{count} story is saved to your profile.";
+"lng_stories_save_done_many#other" = "{count} stories are saved to your profile.";
+"lng_stories_save_done_about" = "Saved stories can be viewed by others on your profile until you remove them.";
+"lng_stories_archive_sure" = "Do you want to hide this story from your profile?";
+"lng_stories_archive_sure_many#one" = "Do you want to hide {count} story from your profile?";
+"lng_stories_archive_sure_many#other" = "Do you want to hide {count} stories from your profile?";
+"lng_stories_archive_done" = "This story is hidden from your profile.";
+"lng_stories_archive_done_many#one" = "{count} story is hidden from your profile.";
+"lng_stories_archive_done_many#other" = "{count} stories are hidden from your profile.";
+
+"lng_stories_link_invalid" = "This link is broken or has expired.";
+
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose Default Program...";
diff --git a/Telegram/Resources/qrc/telegram/export.qrc b/Telegram/Resources/qrc/telegram/export.qrc
index 06ecc7eb7..290d24a30 100644
--- a/Telegram/Resources/qrc/telegram/export.qrc
+++ b/Telegram/Resources/qrc/telegram/export.qrc
@@ -37,6 +37,8 @@
../../export_html/images/section_photos@2x.png
../../export_html/images/section_sessions.png
../../export_html/images/section_sessions@2x.png
+ ../../export_html/images/section_stories.png
+ ../../export_html/images/section_stories@2x.png
../../export_html/images/section_web.png
../../export_html/images/section_web@2x.png
../../export_html/js/script.js
diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml
index 475e3ee7e..898e980a2 100644
--- a/Telegram/Resources/uwp/AppX/AppxManifest.xml
+++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml
@@ -10,7 +10,7 @@
+ Version="4.8.7.0" />
Telegram Desktop
Telegram Messenger LLP
diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc
index cedf12840..68328ffe8 100644
--- a/Telegram/Resources/winrc/Telegram.rc
+++ b/Telegram/Resources/winrc/Telegram.rc
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 4,8,4,0
- PRODUCTVERSION 4,8,4,0
+ FILEVERSION 4,8,7,0
+ PRODUCTVERSION 4,8,7,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
- VALUE "FileVersion", "4.8.4.0"
+ VALUE "FileVersion", "4.8.7.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "4.8.4.0"
+ VALUE "ProductVersion", "4.8.7.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc
index f6f63f644..86b7ee28f 100644
--- a/Telegram/Resources/winrc/Updater.rc
+++ b/Telegram/Resources/winrc/Updater.rc
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 4,8,4,0
- PRODUCTVERSION 4,8,4,0
+ FILEVERSION 4,8,7,0
+ PRODUCTVERSION 4,8,7,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
- VALUE "FileVersion", "4.8.4.0"
+ VALUE "FileVersion", "4.8.7.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "4.8.4.0"
+ VALUE "ProductVersion", "4.8.7.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/SourceFiles/api/api_bot.cpp b/Telegram/SourceFiles/api/api_bot.cpp
index e0a0162ef..2a28bb74c 100644
--- a/Telegram/SourceFiles/api/api_bot.cpp
+++ b/Telegram/SourceFiles/api/api_bot.cpp
@@ -376,8 +376,10 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
ShowAtTheEndMsgId);
auto action = Api::SendAction(history);
action.clearDraft = false;
- action.replyTo = itemId;
- action.topicRootId = topicRootId;
+ action.replyTo = {
+ .msgId = itemId,
+ .topicRootId = topicRootId,
+ };
history->session().api().shareContact(
history->session().user(),
action);
diff --git a/Telegram/SourceFiles/api/api_common.cpp b/Telegram/SourceFiles/api/api_common.cpp
index f4afa97f6..0a44a916f 100644
--- a/Telegram/SourceFiles/api/api_common.cpp
+++ b/Telegram/SourceFiles/api/api_common.cpp
@@ -8,7 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_common.h"
#include "base/qt/qt_key_modifiers.h"
+#include "data/data_histories.h"
#include "data/data_thread.h"
+#include "history/history.h"
namespace Api {
@@ -17,8 +19,8 @@ SendAction::SendAction(
SendOptions options)
: history(thread->owningHistory())
, options(options)
-, replyTo(thread->topicRootId())
-, topicRootId(replyTo) {
+, replyTo({ .msgId = thread->topicRootId() }) {
+ replyTo.topicRootId = replyTo.msgId;
}
SendOptions DefaultSendWhenOnlineOptions() {
@@ -28,4 +30,8 @@ SendOptions DefaultSendWhenOnlineOptions() {
};
}
+MTPInputReplyTo SendAction::mtpReplyTo() const {
+ return Data::ReplyToForMTP(&history->owner(), replyTo);
+}
+
} // namespace Api
diff --git a/Telegram/SourceFiles/api/api_common.h b/Telegram/SourceFiles/api/api_common.h
index 1bdb97ee5..08ee59ca1 100644
--- a/Telegram/SourceFiles/api/api_common.h
+++ b/Telegram/SourceFiles/api/api_common.h
@@ -40,11 +40,12 @@ struct SendAction {
not_null history;
SendOptions options;
- MsgId replyTo = 0;
- MsgId topicRootId = 0;
+ FullReplyTo replyTo;
bool clearDraft = true;
bool generateLocal = true;
MsgId replaceMediaOf = 0;
+
+ [[nodiscard]] MTPInputReplyTo mtpReplyTo() const;
};
struct MessageToSend {
diff --git a/Telegram/SourceFiles/api/api_global_privacy.cpp b/Telegram/SourceFiles/api/api_global_privacy.cpp
index c940dbe86..89e1d57da 100644
--- a/Telegram/SourceFiles/api/api_global_privacy.cpp
+++ b/Telegram/SourceFiles/api/api_global_privacy.cpp
@@ -56,6 +56,15 @@ rpl::producer GlobalPrivacy::archiveAndMute() const {
return _archiveAndMute.value();
}
+UnarchiveOnNewMessage GlobalPrivacy::unarchiveOnNewMessageCurrent() const {
+ return _unarchiveOnNewMessage.current();
+}
+
+auto GlobalPrivacy::unarchiveOnNewMessage() const
+-> rpl::producer {
+ return _unarchiveOnNewMessage.value();
+}
+
rpl::producer GlobalPrivacy::showArchiveAndMute() const {
using namespace rpl::mappers;
@@ -78,11 +87,20 @@ void GlobalPrivacy::dismissArchiveAndMuteSuggestion() {
void GlobalPrivacy::update(bool archiveAndMute) {
using Flag = MTPDglobalPrivacySettings::Flag;
+ const auto unarchive = unarchiveOnNewMessageCurrent();
_api.request(_requestId).cancel();
+ const auto flags = Flag()
+ | (archiveAndMute
+ ? Flag::f_archive_and_mute_new_noncontact_peers
+ : Flag())
+ | (unarchive == UnarchiveOnNewMessage::AnyUnmuted
+ ? Flag::f_keep_archived_unmuted
+ : Flag())
+ | (unarchive != UnarchiveOnNewMessage::None
+ ? Flag::f_keep_archived_folders
+ : Flag());
_requestId = _api.request(MTPaccount_SetGlobalPrivacySettings(
- MTP_globalPrivacySettings(
- MTP_flags(Flag::f_archive_and_mute_new_noncontact_peers),
- MTP_bool(archiveAndMute))
+ MTP_globalPrivacySettings(MTP_flags(flags))
)).done([=](const MTPGlobalPrivacySettings &result) {
_requestId = 0;
apply(result);
@@ -94,9 +112,12 @@ void GlobalPrivacy::update(bool archiveAndMute) {
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) {
data.match([&](const MTPDglobalPrivacySettings &data) {
- _archiveAndMute = data.varchive_and_mute_new_noncontact_peers()
- ? mtpIsTrue(*data.varchive_and_mute_new_noncontact_peers())
- : false;
+ _archiveAndMute = data.is_archive_and_mute_new_noncontact_peers();
+ _unarchiveOnNewMessage = data.is_keep_archived_unmuted()
+ ? UnarchiveOnNewMessage::AnyUnmuted
+ : data.is_keep_archived_folders()
+ ? UnarchiveOnNewMessage::NotInFoldersUnmuted
+ : UnarchiveOnNewMessage::None;
});
}
diff --git a/Telegram/SourceFiles/api/api_global_privacy.h b/Telegram/SourceFiles/api/api_global_privacy.h
index a1a693499..f569951ca 100644
--- a/Telegram/SourceFiles/api/api_global_privacy.h
+++ b/Telegram/SourceFiles/api/api_global_privacy.h
@@ -17,6 +17,12 @@ class Session;
namespace Api {
+enum class UnarchiveOnNewMessage {
+ None,
+ NotInFoldersUnmuted,
+ AnyUnmuted,
+};
+
class GlobalPrivacy final {
public:
explicit GlobalPrivacy(not_null api);
@@ -26,6 +32,10 @@ public:
[[nodiscard]] bool archiveAndMuteCurrent() const;
[[nodiscard]] rpl::producer archiveAndMute() const;
+ [[nodiscard]] auto unarchiveOnNewMessageCurrent() const
+ -> UnarchiveOnNewMessage;
+ [[nodiscard]] auto unarchiveOnNewMessage() const
+ -> rpl::producer;
[[nodiscard]] rpl::producer showArchiveAndMute() const;
[[nodiscard]] rpl::producer<> suggestArchiveAndMute() const;
void dismissArchiveAndMuteSuggestion();
@@ -37,6 +47,8 @@ private:
MTP::Sender _api;
mtpRequestId _requestId = 0;
rpl::variable _archiveAndMute = false;
+ rpl::variable _unarchiveOnNewMessage
+ = UnarchiveOnNewMessage::None;
rpl::variable _showArchiveAndMute = false;
std::vector> _callbacks;
diff --git a/Telegram/SourceFiles/api/api_media.cpp b/Telegram/SourceFiles/api/api_media.cpp
index 7dd916140..ec8c1e4b2 100644
--- a/Telegram/SourceFiles/api/api_media.cpp
+++ b/Telegram/SourceFiles/api/api_media.cpp
@@ -22,8 +22,7 @@ MTPVector ComposeSendingDocumentAttributes(
const auto dimensions = document->dimensions;
auto attributes = QVector(1, filenameAttribute);
if (dimensions.width() > 0 && dimensions.height() > 0) {
- const auto duration = document->getDuration();
- if (duration >= 0 && !document->hasMimeType(u"image/gif"_q)) {
+ if (document->hasDuration() && !document->hasMimeType(u"image/gif"_q)) {
auto flags = MTPDdocumentAttributeVideo::Flags(0);
using VideoFlag = MTPDdocumentAttributeVideo::Flag;
if (document->isVideoMessage()) {
@@ -34,9 +33,10 @@ MTPVector ComposeSendingDocumentAttributes(
}
attributes.push_back(MTP_documentAttributeVideo(
MTP_flags(flags),
- MTP_int(duration),
+ MTP_double(document->duration() / 1000.),
MTP_int(dimensions.width()),
- MTP_int(dimensions.height())));
+ MTP_int(dimensions.height()),
+ MTPint())); // preload_prefix_size
} else {
attributes.push_back(MTP_documentAttributeImageSize(
MTP_int(dimensions.width()),
@@ -56,7 +56,7 @@ MTPVector ComposeSendingDocumentAttributes(
| MTPDdocumentAttributeAudio::Flag::f_performer;
attributes.push_back(MTP_documentAttributeAudio(
MTP_flags(flags),
- MTP_int(song->duration),
+ MTP_int(document->duration() / 1000),
MTP_string(song->title),
MTP_string(song->performer),
MTPstring()));
@@ -65,7 +65,7 @@ MTPVector ComposeSendingDocumentAttributes(
| MTPDdocumentAttributeAudio::Flag::f_waveform;
attributes.push_back(MTP_documentAttributeAudio(
MTP_flags(flags),
- MTP_int(voice->duration),
+ MTP_int(document->duration() / 1000),
MTPstring(),
MTPstring(),
MTP_bytes(documentWaveformEncode5bit(voice->waveform))));
diff --git a/Telegram/SourceFiles/api/api_peer_photo.cpp b/Telegram/SourceFiles/api/api_peer_photo.cpp
index a449b2200..71512172b 100644
--- a/Telegram/SourceFiles/api/api_peer_photo.cpp
+++ b/Telegram/SourceFiles/api/api_peer_photo.cpp
@@ -97,8 +97,7 @@ constexpr auto kSharedMediaLimit = 100;
photo,
photoThumbs,
MTP_documentEmpty(MTP_long(0)),
- jpeg,
- 0);
+ jpeg);
}
[[nodiscard]] std::optional PrepareMtpMarkup(
diff --git a/Telegram/SourceFiles/api/api_polls.cpp b/Telegram/SourceFiles/api/api_polls.cpp
index d18c947c1..227b6e9db 100644
--- a/Telegram/SourceFiles/api/api_polls.cpp
+++ b/Telegram/SourceFiles/api/api_polls.cpp
@@ -43,13 +43,12 @@ void Polls::create(
const auto history = action.history;
const auto peer = history->peer;
- const auto topicRootId = action.replyTo ? action.topicRootId : 0;
+ const auto topicRootId = action.replyTo.msgId
+ ? action.replyTo.topicRootId
+ : 0;
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (action.replyTo) {
- sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
- if (topicRootId) {
- sendFlags |= MTPmessages_SendMedia::Flag::f_top_msg_id;
- }
+ sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
}
const auto clearCloudDraft = action.clearDraft;
if (clearCloudDraft) {
@@ -74,13 +73,11 @@ void Polls::create(
histories.sendPreparedMessage(
history,
action.replyTo,
- topicRootId,
randomId,
Data::Histories::PrepareMessage(
MTP_flags(sendFlags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
- Data::Histories::TopicRootPlaceholder(),
PollDataToInputMedia(&data),
MTP_string(),
MTP_long(randomId),
diff --git a/Telegram/SourceFiles/api/api_report.cpp b/Telegram/SourceFiles/api/api_report.cpp
index 7185b76f5..501870180 100644
--- a/Telegram/SourceFiles/api/api_report.cpp
+++ b/Telegram/SourceFiles/api/api_report.cpp
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
+#include "data/data_user.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/boxes/report_box.h"
@@ -39,11 +40,15 @@ MTPreportReason ReasonToTL(const Ui::ReportReason &reason) {
} // namespace
void SendReport(
- std::shared_ptr show,
- not_null peer,
- Ui::ReportReason reason,
- const QString &comment,
- std::variant> data) {
+ std::shared_ptr show,
+ not_null peer,
+ Ui::ReportReason reason,
+ const QString &comment,
+ std::variant<
+ v::null_t,
+ MessageIdsList,
+ not_null,
+ StoryId> data) {
auto done = [=] {
show->showToast(tr::lng_report_thanks(tr::now));
};
@@ -72,6 +77,17 @@ void SendReport(
ReasonToTL(reason),
MTP_string(comment)
)).done(std::move(done)).send();
+ }, [&](StoryId id) {
+ const auto user = peer->asUser();
+ if (!user) {
+ return;
+ }
+ peer->session().api().request(MTPstories_Report(
+ user->inputUser,
+ MTP_vector(1, MTP_int(id)),
+ ReasonToTL(reason),
+ MTP_string(comment)
+ )).done(std::move(done)).send();
});
}
diff --git a/Telegram/SourceFiles/api/api_report.h b/Telegram/SourceFiles/api/api_report.h
index 08535c00b..14e9d4ef1 100644
--- a/Telegram/SourceFiles/api/api_report.h
+++ b/Telegram/SourceFiles/api/api_report.h
@@ -22,6 +22,10 @@ void SendReport(
not_null peer,
Ui::ReportReason reason,
const QString &comment,
- std::variant> data);
+ std::variant<
+ v::null_t,
+ MessageIdsList,
+ not_null,
+ StoryId> data);
} // namespace Api
diff --git a/Telegram/SourceFiles/api/api_ringtones.cpp b/Telegram/SourceFiles/api/api_ringtones.cpp
index 40b07e3f3..5b471851e 100644
--- a/Telegram/SourceFiles/api/api_ringtones.cpp
+++ b/Telegram/SourceFiles/api/api_ringtones.cpp
@@ -60,8 +60,7 @@ SendMediaReady PrepareRingtoneDocument(
MTP_photoEmpty(MTP_long(0)),
PreparedPhotoThumbs(),
document,
- QByteArray(),
- 0);
+ QByteArray());
}
} // namespace
@@ -203,8 +202,8 @@ int Ringtones::maxSavedCount() const {
100);
}
-int Ringtones::maxDuration() const {
- return _session->account().appConfig().get(
+crl::time Ringtones::maxDuration() const {
+ return crl::time(1000) * _session->account().appConfig().get(
"ringtone_duration_max",
5);
}
diff --git a/Telegram/SourceFiles/api/api_ringtones.h b/Telegram/SourceFiles/api/api_ringtones.h
index 08918a89e..ea97db349 100644
--- a/Telegram/SourceFiles/api/api_ringtones.h
+++ b/Telegram/SourceFiles/api/api_ringtones.h
@@ -40,7 +40,7 @@ public:
[[nodiscard]] int64 maxSize() const;
[[nodiscard]] int maxSavedCount() const;
- [[nodiscard]] int maxDuration() const;
+ [[nodiscard]] crl::time maxDuration() const;
private:
struct UploadedData {
diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp
index dfba1d930..9cfe272f8 100644
--- a/Telegram/SourceFiles/api/api_sending.cpp
+++ b/Telegram/SourceFiles/api/api_sending.cpp
@@ -86,10 +86,7 @@ void SendExistingMedia(
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (message.action.replyTo) {
flags |= MessageFlag::HasReplyInfo;
- sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
- if (message.action.topicRootId) {
- sendFlags |= MTPmessages_SendMedia::Flag::f_top_msg_id;
- }
+ sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
}
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, message.action.options);
@@ -150,13 +147,11 @@ void SendExistingMedia(
histories.sendPreparedMessage(
history,
message.action.replyTo,
- message.action.topicRootId,
randomId,
Data::Histories::PrepareMessage(
MTP_flags(sendFlags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
- Data::Histories::TopicRootPlaceholder(),
inputMedia(),
MTP_string(captionText),
MTP_long(randomId),
@@ -273,10 +268,7 @@ bool SendDice(MessageToSend &message) {
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (message.action.replyTo) {
flags |= MessageFlag::HasReplyInfo;
- sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
- if (message.action.topicRootId) {
- sendFlags |= MTPmessages_SendMedia::Flag::f_top_msg_id;
- }
+ sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
}
const auto replyHeader = NewMessageReplyHeader(message.action);
const auto anonymousPost = peer->amAnonymous();
@@ -320,13 +312,11 @@ bool SendDice(MessageToSend &message) {
histories.sendPreparedMessage(
history,
message.action.replyTo,
- message.action.topicRootId,
randomId,
Data::Histories::PrepareMessage(
MTP_flags(sendFlags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
- Data::Histories::TopicRootPlaceholder(),
MTP_inputMediaDice(MTP_string(emoji)),
MTP_string(),
MTP_long(randomId),
@@ -378,12 +368,12 @@ void SendConfirmedFile(
if (!isEditing) {
const auto histories = &session->data().histories();
- file->to.replyTo = histories->convertTopicReplyTo(
+ file->to.replyTo.msgId = histories->convertTopicReplyToId(
history,
- file->to.replyTo);
- file->to.topicRootId = histories->convertTopicReplyTo(
+ file->to.replyTo.msgId);
+ file->to.replyTo.topicRootId = histories->convertTopicReplyToId(
history,
- file->to.topicRootId);
+ file->to.replyTo.topicRootId);
}
session->uploader().upload(newId, file);
@@ -391,7 +381,6 @@ void SendConfirmedFile(
auto action = SendAction(history, file->to.options);
action.clearDraft = false;
action.replyTo = file->to.replyTo;
- action.topicRootId = file->to.topicRootId;
action.generateLocal = true;
action.replaceMediaOf = file->to.replaceMediaOf;
session->api().sendAction(action);
@@ -453,11 +442,13 @@ void SendConfirmedFile(
MTP_flags(Flag::f_document
| (file->spoiler ? Flag::f_spoiler : Flag())),
file->document,
+ MTPDocument(), // alt_document
MTPint());
} else if (file->type == SendMediaType::Audio) {
return MTP_messageMediaDocument(
MTP_flags(MTPDmessageMediaDocument::Flag::f_document),
file->document,
+ MTPDocument(), // alt_document
MTPint());
} else {
Unexpected("Type in sendFilesConfirmed.");
diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp
index f78a5d9d1..31462da39 100644
--- a/Telegram/SourceFiles/api/api_updates.cpp
+++ b/Telegram/SourceFiles/api/api_updates.cpp
@@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_forum.h"
#include "data/data_scheduled_messages.h"
#include "data/data_send_action.h"
+#include "data/data_stories.h"
#include "data/data_message_reactions.h"
#include "inline_bots/bot_attach_web_view.h"
#include "chat_helpers/emoji_interactions.h"
@@ -679,9 +680,11 @@ void Updates::getDifference() {
api().request(MTPupdates_GetDifference(
MTP_flags(0),
MTP_int(_ptsWaiter.current()),
- MTPint(),
+ MTPint(), // pts_limit
+ MTPint(), // pts_total_limit
MTP_int(_updatesDate),
- MTP_int(_updatesQts)
+ MTP_int(_updatesQts),
+ MTPint() // qts_limit
)).done([=](const MTPupdates_Difference &result) {
differenceDone(result);
}).fail([=](const MTP::Error &error) {
@@ -2545,7 +2548,15 @@ void Updates::feedUpdate(const MTPUpdate &update) {
case mtpc_updateTranscribedAudio: {
const auto &data = update.c_updateTranscribedAudio();
_session->api().transcribes().apply(data);
- }
+ } break;
+
+ case mtpc_updateStory: {
+ _session->data().stories().apply(update.c_updateStory());
+ } break;
+
+ case mtpc_updateReadStories: {
+ _session->data().stories().apply(update.c_updateReadStories());
+ } break;
}
}
diff --git a/Telegram/SourceFiles/api/api_user_privacy.cpp b/Telegram/SourceFiles/api/api_user_privacy.cpp
index 8c97479c6..edaae7c97 100644
--- a/Telegram/SourceFiles/api/api_user_privacy.cpp
+++ b/Telegram/SourceFiles/api/api_user_privacy.cpp
@@ -82,6 +82,8 @@ TLInputRules RulesToTL(const UserPrivacy::Rule &rule) {
switch (rule.option) {
case Option::Everyone: return MTP_inputPrivacyValueAllowAll();
case Option::Contacts: return MTP_inputPrivacyValueAllowContacts();
+ case Option::CloseFriends:
+ return MTP_inputPrivacyValueAllowCloseFriends();
case Option::Nobody: return MTP_inputPrivacyValueDisallowAll();
}
Unexpected("Option value in Api::UserPrivacy::RulesToTL.");
@@ -110,6 +112,8 @@ UserPrivacy::Rule TLToRules(const TLRules &rules, Data::Session &owner) {
setOption(Option::Everyone);
}, [&](const MTPDprivacyValueAllowContacts &) {
setOption(Option::Contacts);
+ }, [&](const MTPDprivacyValueAllowCloseFriends &) {
+ setOption(Option::CloseFriends);
}, [&](const MTPDprivacyValueAllowUsers &data) {
const auto &users = data.vusers().v;
always.reserve(always.size() + users.size());
@@ -177,18 +181,13 @@ MTPInputPrivacyKey KeyToTL(UserPrivacy::Key key) {
case Key::Calls: return MTP_inputPrivacyKeyPhoneCall();
case Key::Invites: return MTP_inputPrivacyKeyChatInvite();
case Key::PhoneNumber: return MTP_inputPrivacyKeyPhoneNumber();
- case Key::AddedByPhone:
- return MTP_inputPrivacyKeyAddedByPhone();
- case Key::LastSeen:
- return MTP_inputPrivacyKeyStatusTimestamp();
- case Key::CallsPeer2Peer:
- return MTP_inputPrivacyKeyPhoneP2P();
- case Key::Forwards:
- return MTP_inputPrivacyKeyForwards();
- case Key::ProfilePhoto:
- return MTP_inputPrivacyKeyProfilePhoto();
- case Key::Voices:
- return MTP_inputPrivacyKeyVoiceMessages();
+ case Key::AddedByPhone: return MTP_inputPrivacyKeyAddedByPhone();
+ case Key::LastSeen: return MTP_inputPrivacyKeyStatusTimestamp();
+ case Key::CallsPeer2Peer: return MTP_inputPrivacyKeyPhoneP2P();
+ case Key::Forwards: return MTP_inputPrivacyKeyForwards();
+ case Key::ProfilePhoto: return MTP_inputPrivacyKeyProfilePhoto();
+ case Key::Voices: return MTP_inputPrivacyKeyVoiceMessages();
+ case Key::About: return MTP_inputPrivacyKeyAbout();
}
Unexpected("Key in Api::UserPrivacy::KetToTL.");
}
@@ -214,6 +213,8 @@ std::optional TLToKey(mtpTypeId type) {
case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto;
case mtpc_privacyKeyVoiceMessages:
case mtpc_inputPrivacyKeyVoiceMessages: return Key::Voices;
+ case mtpc_privacyKeyAbout:
+ case mtpc_inputPrivacyKeyAbout: return Key::About;
}
return std::nullopt;
}
diff --git a/Telegram/SourceFiles/api/api_user_privacy.h b/Telegram/SourceFiles/api/api_user_privacy.h
index 39d8025b5..be8e452d9 100644
--- a/Telegram/SourceFiles/api/api_user_privacy.h
+++ b/Telegram/SourceFiles/api/api_user_privacy.h
@@ -29,10 +29,12 @@ public:
Forwards,
ProfilePhoto,
Voices,
+ About,
};
enum class Option {
Everyone,
Contacts,
+ CloseFriends,
Nobody,
};
struct Rule {
diff --git a/Telegram/SourceFiles/api/api_who_reacted.cpp b/Telegram/SourceFiles/api/api_who_reacted.cpp
index 6fc8800b9..f32358c06 100644
--- a/Telegram/SourceFiles/api/api_who_reacted.cpp
+++ b/Telegram/SourceFiles/api/api_who_reacted.cpp
@@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/controls/who_reacted_context_action.h"
#include "apiwrap.h"
#include "styles/style_chat.h"
+#include "styles/style_chat_helpers.h"
namespace Api {
namespace {
@@ -357,37 +358,6 @@ struct State {
});
}
-[[nodiscard]] QString FormatReadDate(TimeId date, const QDateTime &now) {
- if (!date) {
- return {};
- }
- const auto parsed = base::unixtime::parse(date);
- const auto readDate = parsed.date();
- const auto nowDate = now.date();
- if (readDate == nowDate) {
- return tr::lng_mediaview_today(
- tr::now,
- lt_time,
- QLocale().toString(parsed.time(), QLocale::ShortFormat));
- } else if (readDate.addDays(1) == nowDate) {
- return tr::lng_mediaview_yesterday(
- tr::now,
- lt_time,
- QLocale().toString(parsed.time(), QLocale::ShortFormat));
- }
- return tr::lng_mediaview_date_time(
- tr::now,
- lt_date,
- tr::lng_month_day(
- tr::now,
- lt_month,
- Lang::MonthDay(readDate.month())(tr::now),
- lt_day,
- QString::number(readDate.day())),
- lt_time,
- QLocale().toString(parsed.time(), QLocale::ShortFormat));
-}
-
bool UpdateUserpics(
not_null state,
not_null item,
@@ -614,6 +584,37 @@ rpl::producer WhoReacted(
} // namespace
+QString FormatReadDate(TimeId date, const QDateTime &now) {
+ if (!date) {
+ return {};
+ }
+ const auto parsed = base::unixtime::parse(date);
+ const auto readDate = parsed.date();
+ const auto nowDate = now.date();
+ if (readDate == nowDate) {
+ return tr::lng_mediaview_today(
+ tr::now,
+ lt_time,
+ QLocale().toString(parsed.time(), QLocale::ShortFormat));
+ } else if (readDate.addDays(1) == nowDate) {
+ return tr::lng_mediaview_yesterday(
+ tr::now,
+ lt_time,
+ QLocale().toString(parsed.time(), QLocale::ShortFormat));
+ }
+ return tr::lng_mediaview_date_time(
+ tr::now,
+ lt_date,
+ tr::lng_month_day(
+ tr::now,
+ lt_month,
+ Lang::MonthDay(readDate.month())(tr::now),
+ lt_day,
+ QString::number(readDate.day())),
+ lt_time,
+ QLocale().toString(parsed.time(), QLocale::ShortFormat));
+}
+
bool WhoReadExists(not_null item) {
if (!item->out()) {
return false;
diff --git a/Telegram/SourceFiles/api/api_who_reacted.h b/Telegram/SourceFiles/api/api_who_reacted.h
index 3fdcd8a56..9a9100535 100644
--- a/Telegram/SourceFiles/api/api_who_reacted.h
+++ b/Telegram/SourceFiles/api/api_who_reacted.h
@@ -29,6 +29,7 @@ enum class WhoReactedList {
One,
};
+[[nodiscard]] QString FormatReadDate(TimeId date, const QDateTime &now);
[[nodiscard]] bool WhoReadExists(not_null item);
[[nodiscard]] bool WhoReactedExists(
not_null item,
diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 6348f1718..a469e839e 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -46,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_scheduled_messages.h"
#include "data/data_channel_admins.h"
#include "data/data_session.h"
+#include "data/data_stories.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
@@ -765,9 +766,7 @@ QString ApiWrap::exportDirectMessageLink(
channel->inputChannel,
MTP_int(item->id)
)).done([=](const MTPExportedMessageLink &result) {
- const auto link = result.match([&](const auto &data) {
- return qs(data.vlink());
- });
+ const auto link = qs(result.data().vlink());
if (current != link) {
_unlikelyMessageLinks.emplace_or_assign(itemId, link);
}
@@ -775,6 +774,32 @@ QString ApiWrap::exportDirectMessageLink(
return current;
}
+QString ApiWrap::exportDirectStoryLink(not_null story) {
+ const auto storyId = story->fullId();
+ const auto user = story->peer()->asUser();
+ Assert(user != nullptr);
+ const auto fallback = [&] {
+ const auto base = user->username();
+ const auto story = QString::number(storyId.story);
+ const auto query = base + "/s/" + story;
+ return session().createInternalLinkFull(query);
+ };
+ const auto i = _unlikelyStoryLinks.find(storyId);
+ const auto current = (i != end(_unlikelyStoryLinks))
+ ? i->second
+ : fallback();
+ request(MTPstories_ExportStoryLink(
+ story->peer()->asUser()->inputUser,
+ MTP_int(story->id())
+ )).done([=](const MTPExportedStoryLink &result) {
+ const auto link = qs(result.data().vlink());
+ if (current != link) {
+ _unlikelyStoryLinks.emplace_or_assign(storyId, link);
+ }
+ }).send();
+ return current;
+}
+
void ApiWrap::requestContacts() {
if (_session->data().contactsLoaded().current() || _contactsRequestId) {
return;
@@ -1806,6 +1831,11 @@ void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) {
MTPint(),
MTPNotificationSound(),
MTPNotificationSound(),
+ MTPNotificationSound(),
+ MTPBool(),
+ MTPBool(),
+ MTPNotificationSound(),
+ MTPNotificationSound(),
MTPNotificationSound()));
_notifySettingRequests.erase(key);
}).send();
@@ -2511,6 +2541,15 @@ void ApiWrap::refreshFileReference(
request(MTPaccount_GetSavedRingtones(MTP_long(0)));
}, [&](Data::FileOriginPremiumPreviews data) {
request(MTPhelp_GetPremiumPromo());
+ }, [&](Data::FileOriginStory data) {
+ const auto user = _session->data().peer(data.peerId)->asUser();
+ if (user) {
+ request(MTPstories_GetStoriesByID(
+ user->inputUser,
+ MTP_vector(1, MTP_int(data.storyId))));
+ } else {
+ fail();
+ }
}, [&](v::null_t) {
fail();
});
@@ -3093,8 +3132,9 @@ void ApiWrap::sharedMediaDone(
void ApiWrap::sendAction(const SendAction &action) {
if (!action.options.scheduled && !action.replaceMediaOf) {
- const auto topic = action.topicRootId
- ? action.history->peer->forumTopicFor(action.topicRootId)
+ const auto topicRootId = action.replyTo.topicRootId;
+ const auto topic = topicRootId
+ ? action.history->peer->forumTopicFor(topicRootId)
: nullptr;
if (topic) {
topic->readTillEnd();
@@ -3108,12 +3148,13 @@ void ApiWrap::sendAction(const SendAction &action) {
void ApiWrap::finishForwarding(const SendAction &action) {
const auto history = action.history;
- auto toForward = history->resolveForwardDraft(action.topicRootId);
+ const auto topicRootId = action.replyTo.topicRootId;
+ auto toForward = history->resolveForwardDraft(topicRootId);
if (!toForward.items.empty()) {
const auto error = GetErrorTextForSending(
history->peer,
{
- .topicRootId = action.topicRootId,
+ .topicRootId = topicRootId,
.forward = &toForward.items,
});
if (!error.isEmpty()) {
@@ -3121,7 +3162,7 @@ void ApiWrap::finishForwarding(const SendAction &action) {
}
forwardMessages(std::move(toForward), action);
- history->setForwardDraft(action.topicRootId, {});
+ history->setForwardDraft(topicRootId, {});
}
_session->data().sendHistoryChangeNotifications();
@@ -3165,31 +3206,33 @@ void ApiWrap::forwardMessages(
const auto silentPost = ShouldSendSilent(peer, action.options);
const auto sendAs = action.options.sendAs;
+ using SendFlag = MTPmessages_ForwardMessages::Flag;
auto flags = MessageFlags();
- auto sendFlags = MTPmessages_ForwardMessages::Flags(0);
+ auto sendFlags = SendFlag() | SendFlag();
FillMessagePostFlags(action, peer, flags);
if (silentPost) {
- sendFlags |= MTPmessages_ForwardMessages::Flag::f_silent;
+ sendFlags |= SendFlag::f_silent;
}
if (action.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled;
- sendFlags |= MTPmessages_ForwardMessages::Flag::f_schedule_date;
+ sendFlags |= SendFlag::f_schedule_date;
}
if (draft.options != Data::ForwardOptions::PreserveInfo) {
- sendFlags |= MTPmessages_ForwardMessages::Flag::f_drop_author;
+ sendFlags |= SendFlag::f_drop_author;
}
if (draft.options == Data::ForwardOptions::NoNamesAndCaptions) {
- sendFlags |= MTPmessages_ForwardMessages::Flag::f_drop_media_captions;
+ sendFlags |= SendFlag::f_drop_media_captions;
}
if (sendAs) {
- sendFlags |= MTPmessages_ForwardMessages::Flag::f_send_as;
+ sendFlags |= SendFlag::f_send_as;
}
const auto kGeneralId = Data::ForumTopic::kGeneralId;
- const auto topMsgId = (action.topicRootId == kGeneralId)
+ const auto topicRootId = action.replyTo.topicRootId;
+ const auto topMsgId = (topicRootId == kGeneralId)
? MsgId(0)
- : action.topicRootId;
+ : topicRootId;
if (topMsgId) {
- sendFlags |= MTPmessages_ForwardMessages::Flag::f_top_msg_id;
+ sendFlags |= SendFlag::f_top_msg_id;
}
auto forwardFrom = draft.items.front()->history()->peer;
@@ -3550,14 +3593,14 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
action.generateLocal = true;
sendAction(action);
- const auto replyToId = action.replyTo;
+ const auto replyToId = action.replyTo.msgId;
const auto replyTo = replyToId
? peer->owner().message(peer, replyToId)
: nullptr;
const auto topicRootId = replyTo
? replyTo->topicRootId()
- : action.topicRootId
- ? action.topicRootId
+ : action.replyTo.topicRootId
+ ? action.replyTo.topicRootId
: Data::ForumTopic::kGeneralId;
const auto topic = peer->forumTopicFor(topicRootId);
if (!(topic ? Data::CanSendTexts(topic) : Data::CanSendTexts(peer))
@@ -3596,10 +3639,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
auto sendFlags = MTPmessages_SendMessage::Flags(0);
if (action.replyTo) {
flags |= MessageFlag::HasReplyInfo;
- sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id;
- if (action.topicRootId) {
- sendFlags |= MTPmessages_SendMessage::Flag::f_top_msg_id;
- }
+ sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to;
}
const auto replyHeader = NewMessageReplyHeader(action);
MTPMessageMedia media = MTP_messageMediaEmpty();
@@ -3626,7 +3666,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
sendFlags |= MTPmessages_SendMessage::Flag::f_entities;
}
const auto clearCloudDraft = action.clearDraft;
- const auto topicRootId = action.topicRootId;
+ const auto topicRootId = action.replyTo.topicRootId;
if (clearCloudDraft) {
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
history->clearCloudDraft(topicRootId);
@@ -3663,13 +3703,11 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
histories.sendPreparedMessage(
history,
action.replyTo,
- topicRootId,
randomId,
Data::Histories::PrepareMessage(
MTP_flags(sendFlags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
- Data::Histories::TopicRootPlaceholder(),
msgText,
MTP_long(randomId),
MTPReplyMarkup(),
@@ -3758,29 +3796,29 @@ void ApiWrap::sendInlineResult(
? (*localMessageId)
: _session->data().nextLocalMessageId());
const auto randomId = base::RandomValue();
- const auto topicRootId = action.replyTo ? action.topicRootId : 0;
+ const auto topicRootId = action.replyTo.msgId
+ ? action.replyTo.topicRootId
+ : 0;
+ using SendFlag = MTPmessages_SendInlineBotResult::Flag;
auto flags = NewMessageFlags(peer);
- auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
+ auto sendFlags = SendFlag::f_clear_draft | SendFlag();
if (action.replyTo) {
flags |= MessageFlag::HasReplyInfo;
- sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
- if (topicRootId) {
- sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_top_msg_id;
- }
+ sendFlags |= SendFlag::f_reply_to;
}
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, action.options);
FillMessagePostFlags(action, peer, flags);
if (silentPost) {
- sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_silent;
+ sendFlags |= SendFlag::f_silent;
}
if (action.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled;
- sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_schedule_date;
+ sendFlags |= SendFlag::f_schedule_date;
}
if (action.options.hideViaBot) {
- sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_hide_via;
+ sendFlags |= SendFlag::f_hide_via;
}
const auto sendAs = action.options.sendAs;
@@ -3814,13 +3852,11 @@ void ApiWrap::sendInlineResult(
histories.sendPreparedMessage(
history,
action.replyTo,
- topicRootId,
randomId,
Data::Histories::PrepareMessage(
MTP_flags(sendFlags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
- Data::Histories::TopicRootPlaceholder(),
MTP_long(randomId),
MTP_long(data->getQueryId()),
MTP_string(data->getId()),
@@ -3942,8 +3978,7 @@ void ApiWrap::sendMediaWithRandomId(
}
const auto history = item->history();
- const auto replyTo = item->replyToId();
- const auto topicRootId = item->topicRootId();
+ const auto replyTo = item->replyTo();
auto caption = item->originalText();
TextUtilities::Trim(caption);
@@ -3956,8 +3991,7 @@ void ApiWrap::sendMediaWithRandomId(
using Flag = MTPmessages_SendMedia::Flag;
const auto flags = Flag(0)
- | (replyTo ? Flag::f_reply_to_msg_id : Flag(0))
- | (topicRootId ? Flag::f_top_msg_id : Flag(0))
+ | (replyTo ? Flag::f_reply_to : Flag(0))
| (ShouldSendSilent(history->peer, options)
? Flag::f_silent
: Flag(0))
@@ -3971,13 +4005,11 @@ void ApiWrap::sendMediaWithRandomId(
histories.sendPreparedMessage(
history,
replyTo,
- topicRootId,
randomId,
Data::Histories::PrepareMessage(
MTP_flags(flags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
- Data::Histories::TopicRootPlaceholder(),
media,
MTP_string(caption.text),
MTP_long(randomId),
@@ -4068,13 +4100,11 @@ void ApiWrap::sendAlbumIfReady(not_null album) {
return;
}
const auto history = sample->history();
- const auto replyTo = sample->replyToId();
- const auto topicRootId = sample->topicRootId();
+ const auto replyTo = sample->replyTo();
const auto sendAs = album->options.sendAs;
using Flag = MTPmessages_SendMultiMedia::Flag;
const auto flags = Flag(0)
- | (replyTo ? Flag::f_reply_to_msg_id : Flag(0))
- | (topicRootId ? Flag::f_top_msg_id : Flag(0))
+ | (replyTo ? Flag::f_reply_to : Flag(0))
| (ShouldSendSilent(history->peer, album->options)
? Flag::f_silent
: Flag(0))
@@ -4085,13 +4115,11 @@ void ApiWrap::sendAlbumIfReady(not_null album) {
histories.sendPreparedMessage(
history,
replyTo,
- topicRootId,
uint64(0), // randomId
Data::Histories::PrepareMessage(
MTP_flags(flags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
- Data::Histories::TopicRootPlaceholder(),
MTP_vector(medias),
MTP_int(album->options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
@@ -4114,7 +4142,6 @@ FileLoadTo ApiWrap::fileLoadTaskOptions(const SendAction &action) const {
peer->id,
action.options,
action.replyTo,
- action.topicRootId,
action.replaceMediaOf);
}
diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h
index e747f0f07..dcab7cde8 100644
--- a/Telegram/SourceFiles/apiwrap.h
+++ b/Telegram/SourceFiles/apiwrap.h
@@ -35,6 +35,7 @@ enum class StickersType : uchar;
class Forum;
class ForumTopic;
class Thread;
+class Story;
} // namespace Data
namespace InlineBots {
@@ -160,6 +161,7 @@ public:
QString exportDirectMessageLink(
not_null item,
bool inRepliesContext);
+ QString exportDirectStoryLink(not_null item);
void requestContacts();
void requestDialogs(Data::Folder *folder = nullptr);
@@ -707,5 +709,6 @@ private:
base::flat_map, Fn> _botCommonGroupsRequests;
base::flat_map _unlikelyMessageLinks;
+ base::flat_map _unlikelyStoryLinks;
};
diff --git a/Telegram/SourceFiles/boxes/background_box.cpp b/Telegram/SourceFiles/boxes/background_box.cpp
index e1262b4c9..a7b92aa32 100644
--- a/Telegram/SourceFiles/boxes/background_box.cpp
+++ b/Telegram/SourceFiles/boxes/background_box.cpp
@@ -282,9 +282,9 @@ void BackgroundBox::chosen(const Data::WallPaper &paper) {
close();
});
_controller->show(Ui::MakeConfirmBox({
- .text = u"Are you sure you want to reset the wallpaper?"_q,
+ .text = tr::lng_background_sure_reset_default(),
.confirmed = reset,
- .confirmText = u"Reset"_q,
+ .confirmText = tr::lng_background_reset_default(),
}));
} else {
closeBox();
diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp
index 738a88165..c83af953d 100644
--- a/Telegram/SourceFiles/boxes/background_preview_box.cpp
+++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp
@@ -95,7 +95,7 @@ constexpr auto kDefaultDimming = 50;
const auto flags = MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId
| (out ? MessageFlag::Outgoing : MessageFlag(0));
- const auto replyTo = MsgId();
+ const auto replyTo = FullReplyTo();
const auto viaBotId = UserId();
const auto groupedId = uint64();
const auto item = history->makeMessage(
diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style
index 54f915a45..3758d8a61 100644
--- a/Telegram/SourceFiles/boxes/boxes.style
+++ b/Telegram/SourceFiles/boxes/boxes.style
@@ -24,6 +24,11 @@ UserpicButton {
uploadIcon: icon;
uploadIconPosition: point;
}
+ShortInfoBox {
+ label: FlatLabel;
+ labeled: FlatLabel;
+ labeledOneLine: FlatLabel;
+}
countryRowHeight: 36px;
countryRowNameFont: semiboldFont;
@@ -344,11 +349,6 @@ autoDownloadLimitSlider: MediaSlider(defaultContinuousSlider) {
}
autoDownloadLimitPadding: margins(22px, 8px, 22px, 8px);
-confirmCaptionArea: InputField(defaultInputField) {
- textMargins: margins(1px, 26px, 31px, 4px);
- heightMax: 158px;
-}
-confirmBg: windowBgOver;
confirmMaxHeight: 245px;
supportInfoField: InputField(defaultInputField) {
@@ -391,51 +391,11 @@ sendMediaPreviewSize: 308px;
sendMediaPreviewHeightMax: 1280;
sendMediaRowSkip: 10px;
-editMediaButtonSize: 32px;
-
-editMediaButtonIconFile: icon {{ "send_media/send_media_replace", menuIconFg }};
-editMediaButton: IconButton(defaultIconButton) {
- width: editMediaButtonSize;
- height: editMediaButtonSize;
-
- icon: editMediaButtonIconFile;
-
- rippleAreaSize: editMediaButtonSize;
- ripple: defaultRippleAnimation;
-}
-
editMediaHintLabel: FlatLabel(defaultFlatLabel) {
textFg: windowSubTextFg;
minWidth: sendMediaPreviewSize;
}
-// SendFilesBox
-
-sendBoxAlbumGroupEditInternalSkip: 8px;
-sendBoxAlbumGroupSkipRight: 5px;
-sendBoxAlbumGroupSkipTop: 5px;
-sendBoxAlbumGroupRadius: 4px;
-sendBoxAlbumGroupSize: size(62px, 25px);
-sendBoxAlbumSmallGroupSize: size(30px, 25px);
-
-sendBoxFileGroupSkipTop: 2px;
-sendBoxFileGroupSkipRight: 5px;
-sendBoxFileGroupEditInternalSkip: -1px;
-
-sendBoxAlbumGroupButtonFile: IconButton(editMediaButton) {
- ripple: RippleAnimation(defaultRippleAnimation) {
- color: windowBgRipple;
- }
-}
-sendBoxAlbumGroupEditButtonIconFile: editMediaButtonIconFile;
-sendBoxAlbumGroupDeleteButtonIconFile: icon {{ "send_media/send_media_delete", menuIconFg }};
-
-sendBoxAlbumButtonMediaEdit: icon {{ "send_media/send_media_replace", roundedFg }};
-sendBoxAlbumGroupButtonMediaEdit: icon {{ "send_media/send_media_replace", roundedFg, point(4px, 1px) }};
-sendBoxAlbumGroupButtonMediaDelete: icon {{ "send_media/send_media_delete", roundedFg }};
-
-// End of SendFilesBox
-
calendarTitleHeight: boxTitleHeight;
calendarPrevious: IconButton {
width: calendarTitleHeight;
@@ -982,6 +942,27 @@ requestsBoxList: PeerList(peerListBox) {
padding: margins(0px, 12px, 0px, 12px);
item: requestsBoxItem;
}
+contactsWithStories: PeerList(peerListBox) {
+ padding: margins(0px, 0px, 0px, 0px);
+ item: PeerListItem(peerListBoxItem) {
+ height: 52px;
+ photoPosition: point(18px, 5px);
+ namePosition: point(70px, 7px);
+ statusPosition: point(70px, 27px);
+
+ checkbox: RoundImageCheckbox(defaultPeerListCheckbox) {
+ selectExtendTwice: 1px;
+ imageRadius: 21px;
+ imageSmallRadius: 19px;
+ check: RoundCheckbox(defaultPeerListCheck) {
+ size: 0px;
+ }
+ }
+ nameFgChecked: contactsNameFg;
+ }
+}
+storiesReadLineTwice: 2px;
+storiesUnreadLineTwice: 4px;
requestsAcceptButton: RoundButton(defaultActiveButton) {
width: -28px;
height: 30px;
@@ -1006,3 +987,26 @@ ringtonesBoxSkip: 7px;
gradientButtonGlareDuration: 700;
gradientButtonGlareTimeout: 2000;
gradientButtonGlareWidth: 100px;
+
+infoLabeledOneLine: FlatLabel(defaultFlatLabel) {
+ maxHeight: 20px;
+ style: TextStyle(defaultTextStyle) {
+ lineHeight: 19px;
+ }
+ margin: margins(5px, 5px, 5px, 5px);
+}
+infoLabelSkip: 2px;
+infoLabeled: FlatLabel(infoLabeledOneLine) {
+ minWidth: 180px;
+ maxHeight: 0px;
+ margin: margins(5px, 5px, 5px, 5px);
+}
+infoLabel: FlatLabel(infoLabeled) {
+ textFg: windowSubTextFg;
+}
+
+shortInfoBox: ShortInfoBox {
+ label: infoLabel;
+ labeled: infoLabeled;
+ labeledOneLine: infoLabeledOneLine;
+}
diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
index 41f19a0b8..c9779b1f1 100644
--- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp
+++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
@@ -246,12 +246,12 @@ EditCaptionBox::EditCaptionBox(
, _scroll(base::make_unique_q(this, st::boxScroll))
, _field(base::make_unique_q(
this,
- st::confirmCaptionArea,
+ st::defaultComposeFiles.caption,
Ui::InputField::Mode::MultiLine,
tr::lng_photo_caption()))
, _emojiToggle(base::make_unique_q(
this,
- st::boxAttachEmoji))
+ st::defaultComposeFiles.emoji))
, _initialText(std::move(text))
, _initialList(std::move(list))
, _saved(std::move(saved)) {
@@ -402,6 +402,7 @@ void EditCaptionBox::rebuildPreview() {
if (photo || document->isVideoFile() || document->isAnimation()) {
const auto media = Ui::CreateChild(
this,
+ st::defaultComposeControls,
gifPaused,
_historyItem,
Ui::AttachControls::Type::EditOnly);
@@ -410,6 +411,7 @@ void EditCaptionBox::rebuildPreview() {
} else {
_content.reset(Ui::CreateChild(
this,
+ st::defaultComposeControls,
_historyItem,
Ui::AttachControls::Type::EditOnly));
}
@@ -418,6 +420,7 @@ void EditCaptionBox::rebuildPreview() {
const auto media = Ui::SingleMediaPreview::Create(
this,
+ st::defaultComposeControls,
gifPaused,
file,
Ui::AttachControls::Type::EditOnly);
@@ -429,6 +432,7 @@ void EditCaptionBox::rebuildPreview() {
} else {
_content.reset(Ui::CreateChild(
this,
+ st::defaultComposeControls,
file,
Ui::AttachControls::Type::EditOnly));
}
@@ -482,7 +486,7 @@ void EditCaptionBox::setupField() {
_field->setSubmitSettings(
Core::App().settings().sendSubmitWay());
- _field->setMaxHeight(st::confirmCaptionArea.heightMax);
+ _field->setMaxHeight(st::defaultComposeFiles.caption.heightMax);
connect(_field, &Ui::InputField::submitted, [=] { save(); });
connect(_field, &Ui::InputField::cancelled, [=] { closeBox(); });
@@ -596,7 +600,7 @@ void EditCaptionBox::setupPhotoEditorEventHandler() {
if (!_preparedList.files.empty()) {
Editor::OpenWithPreparedFile(
this,
- controller,
+ controller->uiShow(),
&_preparedList.files.front(),
st::sendMediaPreviewSize,
[=] { rebuildPreview(); });
@@ -845,7 +849,8 @@ bool EditCaptionBox::validateLength(const QString &text) const {
if (remove <= 0) {
return true;
}
- _controller->show(Box(CaptionLimitReachedBox, session, remove));
+ _controller->show(
+ Box(CaptionLimitReachedBox, session, remove, nullptr));
return false;
}
diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp
index dfa6b3707..51be4cd11 100644
--- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp
+++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp
@@ -112,10 +112,16 @@ std::unique_ptr PrivacyExceptionsBoxControl
} // namespace
+bool EditPrivacyController::hasOption(Option option) const {
+ return (option != Option::CloseFriends);
+}
+
QString EditPrivacyController::optionLabel(Option option) const {
switch (option) {
case Option::Everyone: return tr::lng_edit_privacy_everyone(tr::now);
case Option::Contacts: return tr::lng_edit_privacy_contacts(tr::now);
+ case Option::CloseFriends:
+ return tr::lng_edit_privacy_close_friends(tr::now);
case Option::Nobody: return tr::lng_edit_privacy_nobody(tr::now);
}
Unexpected("Option value in optionsLabelKey.");
@@ -182,10 +188,12 @@ bool EditPrivacyBox::showExceptionLink(Exception exception) const {
switch (exception) {
case Exception::Always:
return (_value.option == Option::Contacts)
+ || (_value.option == Option::CloseFriends)
|| (_value.option == Option::Nobody);
case Exception::Never:
return (_value.option == Option::Everyone)
- || (_value.option == Option::Contacts);
+ || (_value.option == Option::Contacts)
+ || (_value.option == Option::CloseFriends);
}
Unexpected("Invalid exception value.");
}
@@ -326,6 +334,7 @@ void EditPrivacyBox::setupContent() {
{ 0, st::settingsPrivacySkipTop, 0, 0 });
addOptionRow(Option::Everyone);
addOptionRow(Option::Contacts);
+ addOptionRow(Option::CloseFriends);
addOptionRow(Option::Nobody);
const auto warning = addLabelOrDivider(
content,
diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.h b/Telegram/SourceFiles/boxes/edit_privacy_box.h
index 6a78c41ae..d9ba7dab9 100644
--- a/Telegram/SourceFiles/boxes/edit_privacy_box.h
+++ b/Telegram/SourceFiles/boxes/edit_privacy_box.h
@@ -41,9 +41,7 @@ public:
[[nodiscard]] virtual Key key() const = 0;
[[nodiscard]] virtual rpl::producer title() const = 0;
- [[nodiscard]] virtual bool hasOption(Option option) const {
- return true;
- }
+ [[nodiscard]] virtual bool hasOption(Option option) const;
[[nodiscard]] virtual rpl::producer optionsTitleKey() const = 0;
[[nodiscard]] virtual QString optionLabel(Option option) const;
[[nodiscard]] virtual rpl::producer warning() const {
diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp
index 8e393c583..6cce77d60 100644
--- a/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp
+++ b/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp
@@ -309,7 +309,7 @@ object_ptr CreatePeerListSectionSubtitle(
rpl::producer text) {
auto result = object_ptr(
parent,
- st::searchedBarHeight);
+ st::windowFilterChatsSectionSubtitleHeight);
const auto raw = result.data();
raw->paintRequest(
diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp
index 66f10501a..6f27553d0 100644
--- a/Telegram/SourceFiles/boxes/peer_list_box.cpp
+++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp
@@ -10,13 +10,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/session/session_show.h"
#include "main/main_session.h"
#include "mainwidget.h"
+#include "ui/effects/loading_element.h"
+#include "ui/effects/outline_segments.h"
+#include "ui/effects/round_checkbox.h"
+#include "ui/effects/ripple_animation.h"
#include "ui/widgets/multi_select.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/popup_menu.h"
-#include "ui/effects/loading_element.h"
-#include "ui/effects/round_checkbox.h"
-#include "ui/effects/ripple_animation.h"
#include "ui/empty_userpic.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/text/text_options.h"
@@ -33,8 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_dialogs.h"
#include "styles/style_widgets.h"
-#include
-
PaintRoundImageCallback PaintUserpicCallback(
not_null peer,
bool respectSavedMessagesChat) {
@@ -263,15 +262,23 @@ void PeerListBox::peerListSetRowChecked(
not_null row,
bool checked) {
if (checked) {
- addSelectItem(row, anim::type::normal);
+ if (_controller->trackSelectedList()) {
+ addSelectItem(row, anim::type::normal);
+ }
PeerListContentDelegate::peerListSetRowChecked(row, checked);
peerListUpdateRow(row);
// This call deletes row from _searchRows.
- _select->entity()->clearQuery();
+ if (_select) {
+ _select->entity()->clearQuery();
+ }
} else {
// The itemRemovedCallback will call changeCheckState() here.
- _select->entity()->removeItem(row->id());
+ if (_select) {
+ _select->entity()->removeItem(row->id());
+ } else {
+ PeerListContentDelegate::peerListSetRowChecked(row, checked);
+ }
peerListUpdateRow(row);
}
}
@@ -882,9 +889,18 @@ void PeerListRow::createCheckbox(
}
void PeerListRow::setCheckedInternal(bool checked, anim::type animated) {
+ Expects(!checked || _checkbox != nullptr);
+
+ if (_checkbox) {
+ _checkbox->setChecked(checked, animated);
+ }
+}
+
+void PeerListRow::setCustomizedCheckSegments(
+ std::vector segments) {
Expects(_checkbox != nullptr);
- _checkbox->setChecked(checked, animated);
+ _checkbox->setCustomizedSegments(std::move(segments));
}
void PeerListRow::finishCheckedAnimation() {
@@ -1126,6 +1142,24 @@ PeerListRow *PeerListContent::findRow(PeerListRowId id) {
return (it == _rowsById.cend()) ? nullptr : it->second.get();
}
+std::optional PeerListContent::lastRowMousePosition() const {
+ if (!_lastMousePosition) {
+ return std::nullopt;
+ }
+ const auto point = mapFromGlobal(*_lastMousePosition);
+ auto in = parentWidget()->rect().contains(
+ parentWidget()->mapFromGlobal(*_lastMousePosition));
+ auto rowsPointY = point.y() - rowsTop();
+ const auto index = (in
+ && rowsPointY >= 0
+ && rowsPointY < shownRowsCount() * _rowHeight)
+ ? (rowsPointY / _rowHeight)
+ : -1;
+ return (index >= 0 && index == _selected.index.value)
+ ? QPoint(point.x(), rowsPointY)
+ : std::optional();
+}
+
void PeerListContent::removeRow(not_null row) {
auto index = row->absoluteIndex();
auto isSearchResult = row->isSearchResult();
@@ -1254,6 +1288,9 @@ void PeerListContent::initDecorateWidget(Ui::RpWidget *widget) {
}) | rpl::start_with_next([=] {
mouseLeftGeometry();
}, widget->lifetime());
+ widget->heightValue() | rpl::skip(1) | rpl::start_with_next([=] {
+ resizeToWidth(width());
+ }, widget->lifetime());
}
}
@@ -1990,10 +2027,12 @@ void PeerListContent::setSearchQuery(
bool PeerListContent::submitted() {
if (const auto row = getRow(_selected.index)) {
+ _lastMousePosition = std::nullopt;
_controller->rowClicked(row);
return true;
} else if (showingSearch()) {
if (const auto row = getRow(RowIndex(0))) {
+ _lastMousePosition = std::nullopt;
_controller->rowClicked(row);
return true;
}
diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h
index 28cb69534..ac8ab554b 100644
--- a/Telegram/SourceFiles/boxes/peer_list_box.h
+++ b/Telegram/SourceFiles/boxes/peer_list_box.h
@@ -36,6 +36,7 @@ class SlideWrap;
class FlatLabel;
struct ScrollToRequest;
class PopupMenu;
+struct OutlineSegment;
} // namespace Ui
using PaintRoundImageCallback = Fn segments);
void setHidden(bool hidden) {
_hidden = hidden;
}
@@ -324,6 +327,7 @@ public:
virtual void peerListScrollToTop() = 0;
virtual int peerListFullRowsCount() = 0;
virtual PeerListRow *peerListFindRow(PeerListRowId id) = 0;
+ virtual std::optional peerListLastRowMousePosition() = 0;
virtual void peerListSortRows(Fn compare) = 0;
virtual int peerListPartitionRows(Fn border) = 0;
virtual void peerListShowBox(
@@ -500,6 +504,9 @@ public:
return delegate()->peerListIsRowChecked(row);
}
+ virtual bool trackSelectedList() {
+ return true;
+ }
virtual bool searchInLocal() {
return true;
}
@@ -609,6 +616,7 @@ public:
void prependRow(std::unique_ptr row);
void prependRowFromSearchResult(not_null row);
PeerListRow *findRow(PeerListRowId id);
+ std::optional lastRowMousePosition() const;
void updateRow(not_null row) {
updateRow(row, RowIndex());
}
@@ -863,6 +871,9 @@ public:
PeerListRow *peerListFindRow(PeerListRowId id) override {
return _content->findRow(id);
}
+ std::optional peerListLastRowMousePosition() override {
+ return _content->lastRowMousePosition();
+ }
void peerListUpdateRow(not_null row) override {
_content->updateRow(row);
}
diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp
index 0679d4dc9..5831ec0b5 100644
--- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp
+++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp
@@ -9,12 +9,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_chat_participants.h"
#include "base/random.h"
+#include "boxes/filters/edit_filter_chats_list.h"
#include "ui/boxes/confirm_box.h"
+#include "ui/effects/round_checkbox.h"
+#include "ui/widgets/menu/menu_add_action_callback_factory.h"
#include "ui/widgets/checkbox.h"
+#include "ui/widgets/popup_menu.h"
+#include "ui/wrap/padding_wrap.h"
#include "ui/painter.h"
#include "ui/ui_utility.h"
#include "main/main_session.h"
#include "data/data_session.h"
+#include "data/data_stories.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
@@ -31,12 +37,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "history/history_item.h"
#include "dialogs/dialogs_main_list.h"
+#include "ui/effects/outline_segments.h"
+#include "ui/wrap/slide_wrap.h"
#include "window/window_session_controller.h" // showAddContact()
#include "base/unixtime.h"
#include "styles/style_boxes.h"
#include "styles/style_profile.h"
#include "styles/style_dialogs.h"
+#include "data/data_stories.h"
+#include "dialogs/ui/dialogs_stories_content.h"
+#include "dialogs/ui/dialogs_stories_list.h"
+
namespace {
constexpr auto kSortByOnlineThrottle = 3 * crl::time(1000);
@@ -49,21 +61,26 @@ object_ptr PrepareContactsBox(
using Mode = ContactsBoxController::SortMode;
auto controller = std::make_unique(
&sessionController->session());
+ controller->setStyleOverrides(&st::contactsWithStories);
+ controller->setStoriesShown(true);
const auto raw = controller.get();
auto init = [=](not_null box) {
struct State {
- QPointer toggleSort;
- Mode mode = ContactsBoxController::SortMode::Online;
+ QPointer<::Ui::IconButton> toggleSort;
+ rpl::variable mode = Mode::Online;
+ ::Ui::Animations::Simple scrollAnimation;
};
+
const auto state = box->lifetime().make_state();
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
box->addLeftButton(
tr::lng_profile_add_contact(),
[=] { sessionController->showAddContact(); });
state->toggleSort = box->addTopButton(st::contactsSortButton, [=] {
- const auto online = (state->mode == Mode::Online);
- state->mode = online ? Mode::Alphabet : Mode::Online;
- raw->setSortMode(state->mode);
+ const auto online = (state->mode.current() == Mode::Online);
+ const auto mode = online ? Mode::Alphabet : Mode::Online;
+ state->mode = mode;
+ raw->setSortMode(mode);
state->toggleSort->setIconOverride(
online ? &st::contactsSortOnlineIcon : nullptr,
online ? &st::contactsSortOnlineIconOver : nullptr);
@@ -73,6 +90,39 @@ object_ptr PrepareContactsBox(
return Box(std::move(controller), std::move(init));
}
+QBrush PeerListStoriesGradient(const style::PeerList &st) {
+ const auto left = st.item.photoPosition.x();
+ const auto top = st.item.photoPosition.y();
+ const auto size = st.item.photoSize;
+ return Ui::UnreadStoryOutlineGradient(QRectF(left, top, size, size));
+}
+
+std::vector PeerListStoriesSegments(
+ int count,
+ int unread,
+ const QBrush &unreadBrush) {
+ Expects(unread <= count);
+ Expects(count > 0);
+
+ auto result = std::vector();
+ const auto add = [&](bool unread) {
+ result.push_back({
+ .brush = unread ? unreadBrush : st::dialogsUnreadBgMuted->b,
+ .width = (unread
+ ? st::dialogsStoriesFull.lineTwice / 2.
+ : st::dialogsStoriesFull.lineReadTwice / 2.),
+ });
+ };
+ result.reserve(count);
+ for (auto i = 0, till = count - unread; i != till; ++i) {
+ add(false);
+ }
+ for (auto i = 0; i != unread; ++i) {
+ add(true);
+ }
+ return result;
+}
+
void PeerListRowWithLink::setActionLink(const QString &action) {
_action = action;
refreshActionLink();
@@ -308,6 +358,115 @@ bool ChatsListBoxController::appendRow(not_null history) {
return false;
}
+PeerListStories::PeerListStories(
+ not_null controller,
+ not_null session)
+: _controller(controller)
+, _session(session) {
+}
+
+void PeerListStories::updateColors() {
+ for (auto i = begin(_counts); i != end(_counts); ++i) {
+ if (const auto row = _delegate->peerListFindRow(i->first)) {
+ if (i->second.count >= 0 && i->second.unread >= 0) {
+ applyForRow(row, i->second.count, i->second.unread, true);
+ }
+ }
+ }
+}
+
+void PeerListStories::updateFor(
+ uint64 id,
+ int count,
+ int unread) {
+ if (const auto row = _delegate->peerListFindRow(id)) {
+ applyForRow(row, count, unread);
+ _delegate->peerListUpdateRow(row);
+ }
+}
+
+void PeerListStories::process(not_null row) {
+ const auto user = row->peer()->asUser();
+ if (!user) {
+ return;
+ }
+ const auto stories = &_session->data().stories();
+ const auto source = stories->source(user->id);
+ const auto count = source
+ ? int(source->ids.size())
+ : user->hasActiveStories()
+ ? 1
+ : 0;
+ const auto unread = source
+ ? source->info().unreadCount
+ : user->hasUnreadStories()
+ ? 1
+ : 0;
+ applyForRow(row, count, unread, true);
+}
+
+bool PeerListStories::handleClick(not_null peer) {
+ const auto point = _delegate->peerListLastRowMousePosition();
+ const auto &st = _controller->listSt()->item;
+ if (point && point->x() < st.photoPosition.x() + st.photoSize) {
+ if (const auto window = peer->session().tryResolveWindow()) {
+ if (const auto user = peer->asUser()) {
+ if (user->hasActiveStories()) {
+ window->openPeerStories(peer->id);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void PeerListStories::prepare(not_null delegate) {
+ _delegate = delegate;
+
+ _unreadBrush = PeerListStoriesGradient(*_controller->listSt());
+ style::PaletteChanged() | rpl::start_with_next([=] {
+ _unreadBrush = PeerListStoriesGradient(*_controller->listSt());
+ updateColors();
+ }, _lifetime);
+
+ _session->changes().peerUpdates(
+ Data::PeerUpdate::Flag::StoriesState
+ ) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
+ const auto id = update.peer->id.value;
+ if (const auto row = _delegate->peerListFindRow(id)) {
+ process(row);
+ }
+ }, _lifetime);
+
+ const auto stories = &_session->data().stories();
+ stories->sourceChanged() | rpl::start_with_next([=](PeerId id) {
+ const auto source = stories->source(id);
+ const auto info = source
+ ? source->info()
+ : Data::StoriesSourceInfo();
+ updateFor(id.value, info.count, info.unreadCount);
+ }, _lifetime);
+}
+
+void PeerListStories::applyForRow(
+ not_null row,
+ int count,
+ int unread,
+ bool force) {
+ auto &counts = _counts[row->id()];
+ if (!force && counts.count == count && counts.unread == unread) {
+ return;
+ }
+ counts.count = count;
+ counts.unread = unread;
+ _delegate->peerListSetRowChecked(row, count > 0);
+ if (count > 0) {
+ row->setCustomizedCheckSegments(
+ PeerListStoriesSegments(count, unread, _unreadBrush));
+ }
+}
+
ContactsBoxController::ContactsBoxController(
not_null session)
: ContactsBoxController(
@@ -334,6 +493,10 @@ void ContactsBoxController::prepare() {
prepareViewHook();
+ if (_stories) {
+ _stories->prepare(delegate());
+ }
+
session().data().contactsLoaded().value(
) | rpl::start_with_next([=] {
rebuildRows();
@@ -378,8 +541,10 @@ std::unique_ptr ContactsBoxController::createSearchRow(
void ContactsBoxController::rowClicked(not_null row) {
const auto peer = row->peer();
- if (const auto window = peer->session().tryResolveWindow()) {
- window->showPeerHistory(row->peer());
+ if (_stories && _stories->handleClick(peer)) {
+ return;
+ } else if (const auto window = peer->session().tryResolveWindow()) {
+ window->showPeerHistory(peer);
}
}
@@ -404,6 +569,10 @@ void ContactsBoxController::setSortMode(SortMode mode) {
}
}
+void ContactsBoxController::setStoriesShown(bool shown) {
+ _stories = std::make_unique(this, _session);
+}
+
void ContactsBoxController::sort() {
switch (_sortMode) {
case SortMode::Alphabet: sortByName(); break;
@@ -449,7 +618,11 @@ bool ContactsBoxController::appendRow(not_null user) {
return false;
}
if (auto row = createRow(user)) {
+ const auto raw = row.get();
delegate()->peerListAppendRow(std::move(row));
+ if (_stories) {
+ _stories->process(raw);
+ }
return true;
}
return false;
diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.h b/Telegram/SourceFiles/boxes/peer_list_controllers.h
index 00106c392..0ba108f01 100644
--- a/Telegram/SourceFiles/boxes/peer_list_controllers.h
+++ b/Telegram/SourceFiles/boxes/peer_list_controllers.h
@@ -20,12 +20,21 @@ class Forum;
class ForumTopic;
} // namespace Data
+namespace Ui {
+struct OutlineSegment;
+} // namespace Ui
+
namespace Window {
class SessionController;
} // namespace Window
[[nodiscard]] object_ptr PrepareContactsBox(
not_null sessionController);
+[[nodiscard]] QBrush PeerListStoriesGradient(const style::PeerList &st);
+[[nodiscard]] std::vector PeerListStoriesSegments(
+ int count,
+ int unread,
+ const QBrush &unreadBrush);
class PeerListRowWithLink : public PeerListRow {
public:
@@ -116,6 +125,41 @@ private:
};
+class PeerListStories final {
+public:
+ PeerListStories(
+ not_null controller,
+ not_null session);
+
+ void prepare(not_null delegate);
+
+ void process(not_null row);
+ bool handleClick(not_null peer);
+
+private:
+ struct Counts {
+ int count = 0;
+ int unread = 0;
+ };
+
+ void updateColors();
+ void updateFor(uint64 id, int count, int unread);
+ void applyForRow(
+ not_null row,
+ int count,
+ int unread,
+ bool force = false);
+
+ const not_null _controller;
+ const not_null _session;
+ PeerListDelegate *_delegate = nullptr;
+
+ QBrush _unreadBrush;
+ base::flat_map _counts;
+ rpl::lifetime _lifetime;
+
+};
+
class ContactsBoxController : public PeerListController {
public:
explicit ContactsBoxController(not_null session);
@@ -128,12 +172,16 @@ public:
[[nodiscard]] std::unique_ptr createSearchRow(
not_null peer) override final;
void rowClicked(not_null row) override;
+ bool trackSelectedList() override {
+ return !_stories;
+ }
enum class SortMode {
Alphabet,
Online,
};
void setSortMode(SortMode mode);
+ void setStoriesShown(bool shown);
protected:
virtual std::unique_ptr createRow(not_null user);
@@ -155,6 +203,8 @@ private:
base::Timer _sortByOnlineTimer;
rpl::lifetime _sortByOnlineLifetime;
+ std::unique_ptr _stories;
+
};
class ChooseRecipientBoxController
diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp
index 94caec150..e1d09efec 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp
@@ -25,11 +25,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/dialogs_indexed_list.h"
#include "data/data_peer_values.h"
#include "data/data_session.h"
+#include "data/data_stories.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "data/data_changes.h"
#include "base/unixtime.h"
+#include "ui/effects/outline_segments.h"
#include "ui/widgets/popup_menu.h"
#include "ui/ui_utility.h"
#include "info/profile/info_profile_values.h"
@@ -900,7 +902,11 @@ void ParticipantsBoxController::setupListChangeViewers() {
return (row.peer() == user);
});
} else if (auto row = createRow(user)) {
+ const auto raw = row.get();
delegate()->peerListPrependRow(std::move(row));
+ if (_stories) {
+ _stories->process(raw);
+ }
refreshRows();
if (_onlineSorter) {
_onlineSorter->sort();
@@ -1159,9 +1165,19 @@ void ParticipantsBoxController::restoreState(
if (my->wasLoading) {
loadMoreRows();
}
+ const auto was = _fullCountValue.current();
PeerListController::restoreState(std::move(state));
- if (delegate()->peerListFullRowsCount() > 0 || _allLoaded) {
+ const auto now = delegate()->peerListFullRowsCount();
+ if (now > 0 || _allLoaded) {
refreshDescription();
+ if (_stories) {
+ for (auto i = 0; i != now; ++i) {
+ _stories->process(delegate()->peerListRowAt(i));
+ }
+ }
+ if (now != was) {
+ refreshRows();
+ }
}
if (_onlineSorter) {
_onlineSorter->sort();
@@ -1177,14 +1193,21 @@ rpl::producer ParticipantsBoxController::fullCountValue() const {
return _fullCountValue.value();
}
+void ParticipantsBoxController::setStoriesShown(bool shown) {
+ _stories = std::make_unique(
+ this,
+ &_navigation->session());
+}
+
void ParticipantsBoxController::prepare() {
auto title = [&] {
switch (_role) {
case Role::Admins: return tr::lng_channel_admins();
case Role::Profile:
- case Role::Members: return (_peer->isChannel() && !_peer->isMegagroup()
- ? tr::lng_profile_subscribers_section()
- : tr::lng_profile_participants_section());
+ case Role::Members:
+ return ((_peer->isChannel() && !_peer->isMegagroup())
+ ? tr::lng_profile_subscribers_section()
+ : tr::lng_profile_participants_section());
case Role::Restricted: return tr::lng_exceptions_list_title();
case Role::Kicked: return tr::lng_removed_list_title();
}
@@ -1207,6 +1230,10 @@ void ParticipantsBoxController::prepare() {
setDescriptionText(tr::lng_contacts_loading(tr::now));
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
+ if (_stories) {
+ _stories->prepare(delegate());
+ }
+
if (_role == Role::Profile) {
auto visible = _peer->isMegagroup()
? Info::Profile::CanViewParticipantsValue(_peer->asMegagroup())
@@ -1318,8 +1345,14 @@ void ParticipantsBoxController::rebuildChatParticipants(
}
}
for (const auto &user : participants) {
- if (auto row = createRow(user)) {
- delegate()->peerListAppendRow(std::move(row));
+ if (!delegate()->peerListFindRow(user->id.value)) {
+ if (auto row = createRow(user)) {
+ const auto raw = row.get();
+ delegate()->peerListAppendRow(std::move(row));
+ if (_stories) {
+ _stories->process(raw);
+ }
+ }
}
}
_onlineSorter->sort();
@@ -1373,7 +1406,11 @@ void ParticipantsBoxController::rebuildChatAdmins(
}
for (const auto user : list) {
if (auto row = createRow(user)) {
+ const auto raw = row.get();
delegate()->peerListAppendRow(std::move(row));
+ if (_stories) {
+ _stories->process(raw);
+ }
}
}
@@ -1543,6 +1580,11 @@ bool ParticipantsBoxController::feedMegagroupLastParticipants() {
void ParticipantsBoxController::rowClicked(not_null row) {
const auto participant = row->peer();
const auto user = participant->asUser();
+
+ if (_stories && _stories->handleClick(participant)) {
+ return;
+ }
+
if (_role == Role::Admins) {
Assert(user != nullptr);
showAdmin(user);
@@ -1890,7 +1932,11 @@ bool ParticipantsBoxController::appendRow(not_null participant) {
recomputeTypeFor(participant);
return false;
} else if (auto row = createRow(participant)) {
+ const auto raw = row.get();
delegate()->peerListAppendRow(std::move(row));
+ if (_stories) {
+ _stories->process(raw);
+ }
if (_role != Role::Kicked) {
setDescriptionText(QString());
}
@@ -1906,10 +1952,17 @@ bool ParticipantsBoxController::prependRow(not_null participant) {
if (_role == Role::Admins) {
// Perhaps we've added a new admin from search.
delegate()->peerListPrependRowFromSearchResult(row);
+ if (_stories) {
+ _stories->process(row);
+ }
}
return false;
} else if (auto row = createRow(participant)) {
+ const auto raw = row.get();
delegate()->peerListPrependRow(std::move(row));
+ if (_stories) {
+ _stories->process(raw);
+ }
if (_role != Role::Kicked) {
setDescriptionText(QString());
}
diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.h b/Telegram/SourceFiles/boxes/peers/edit_participants_box.h
index 30b445813..0882f214a 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.h
+++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.h
@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/weak_ptr.h"
#include "info/profile/info_profile_members_controllers.h"
+class PeerListStories;
struct ChatAdminRightsInfo;
struct ChatRestrictionsInfo;
@@ -174,6 +175,9 @@ public:
QWidget *parent,
not_null row) override;
void loadMoreRows() override;
+ bool trackSelectedList() override {
+ return !_stories;
+ }
void peerListSearchAddRow(not_null peer) override;
std::unique_ptr createSearchRow(
@@ -187,6 +191,8 @@ public:
[[nodiscard]] rpl::producer onlineCountValue() const;
[[nodiscard]] rpl::producer fullCountValue() const;
+ void setStoriesShown(bool shown);
+
protected:
// Allow child controllers not providing navigation.
// This is their responsibility to override all methods that use it.
@@ -288,6 +294,8 @@ private:
Ui::BoxPointer _addBox;
QPointer _editParticipantBox;
+ std::unique_ptr _stories;
+
};
// Members, banned and restricted users server side search.
diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp
index 619542edb..1bf236db1 100644
--- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/streaming/media_streaming_player.h"
#include "base/event_filter.h"
#include "lang/lang_keys.h"
+#include "styles/style_boxes.h"
#include "styles/style_layers.h"
#include "styles/style_info.h"
@@ -614,8 +615,10 @@ PeerShortInfoBox::PeerShortInfoBox(
rpl::producer fields,
rpl::producer status,
rpl::producer userpic,
- Fn videoPaused)
-: _type(type)
+ Fn videoPaused,
+ const style::ShortInfoBox *stOverride)
+: _st(stOverride ? *stOverride : st::shortInfoBox)
+, _type(type)
, _fields(std::move(fields))
, _topRoundBackground(this)
, _scroll(this, st::shortInfoScroll)
@@ -691,11 +694,12 @@ void PeerShortInfoBox::prepareRows() {
auto addInfoLineGeneric = [&](
rpl::producer &&label,
rpl::producer &&text,
- const style::FlatLabel &textSt = st::infoLabeled) {
+ const style::FlatLabel &textSt) {
auto line = CreateTextWithLabel(
_rows,
rpl::duplicate(label) | Ui::Text::ToWithEntities(),
rpl::duplicate(text),
+ _st.label,
textSt,
st::shortInfoLabeledPadding);
_rows->add(object_ptr(
@@ -715,7 +719,7 @@ void PeerShortInfoBox::prepareRows() {
auto addInfoLine = [&](
rpl::producer &&label,
rpl::producer &&text,
- const style::FlatLabel &textSt = st::infoLabeled) {
+ const style::FlatLabel &textSt) {
return addInfoLineGeneric(
std::move(label),
std::move(text),
@@ -728,7 +732,7 @@ void PeerShortInfoBox::prepareRows() {
auto result = addInfoLine(
std::move(label),
std::move(text),
- st::infoLabeledOneLine);
+ _st.labeledOneLine);
result->setDoubleClickSelectsParagraph(true);
result->setContextCopyText(contextCopyText);
return result;
@@ -744,7 +748,7 @@ void PeerShortInfoBox::prepareRows() {
auto label = _fields.current().isBio
? tr::lng_info_bio_label()
: tr::lng_info_about_label();
- addInfoLine(std::move(label), aboutValue());
+ addInfoLine(std::move(label), aboutValue(), _st.labeled);
addInfoOneLine(
tr::lng_info_username_label(),
usernameValue() | Ui::Text::ToWithEntities(),
diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h
index fc29b7062..07e60132a 100644
--- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h
+++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace style {
struct ShortInfoCover;
+struct ShortInfoBox;
} // namespace style
namespace Media::Streaming {
@@ -144,7 +145,8 @@ public:
rpl::producer fields,
rpl::producer status,
rpl::producer userpic,
- Fn videoPaused);
+ Fn videoPaused,
+ const style::ShortInfoBox *stOverride);
~PeerShortInfoBox();
[[nodiscard]] rpl::producer<> openRequests() const;
@@ -166,6 +168,7 @@ private:
[[nodiscard]] rpl::producer usernameValue() const;
[[nodiscard]] rpl::producer aboutValue() const;
+ const style::ShortInfoBox &_st;
const PeerShortInfoType _type = PeerShortInfoType::User;
rpl::variable _fields;
diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp
index a39b7eb47..8baf378b5 100644
--- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp
@@ -420,7 +420,8 @@ bool ProcessCurrent(
object_ptr PrepareShortInfoBox(
not_null peer,
Fn open,
- Fn videoPaused) {
+ Fn videoPaused,
+ const style::ShortInfoBox *stOverride) {
const auto type = peer->isUser()
? PeerShortInfoType::User
: peer->isBroadcast()
@@ -432,7 +433,8 @@ object_ptr PrepareShortInfoBox(
FieldsValue(peer),
StatusValue(peer),
std::move(userpic.value),
- std::move(videoPaused));
+ std::move(videoPaused),
+ stOverride);
result->openRequests(
) | rpl::start_with_next(open, result->lifetime());
@@ -445,7 +447,8 @@ object_ptr PrepareShortInfoBox(
object_ptr PrepareShortInfoBox(
not_null peer,
- not_null navigation) {
+ not_null navigation,
+ const style::ShortInfoBox *stOverride) {
const auto open = [=] { navigation->showPeerHistory(peer); };
const auto videoIsPaused = [=] {
return navigation->parentController()->isGifPausedAtLeastFor(
@@ -454,7 +457,8 @@ object_ptr PrepareShortInfoBox(
return PrepareShortInfoBox(
peer,
open,
- videoIsPaused);
+ videoIsPaused,
+ stOverride);
}
rpl::producer PrepareShortInfoStatus(not_null peer) {
diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.h b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.h
index f50a23bf7..327ce373b 100644
--- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.h
+++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.h
@@ -13,6 +13,7 @@ class PeerData;
namespace style {
struct ShortInfoCover;
+struct ShortInfoBox;
} // namespace style
namespace Ui {
@@ -33,11 +34,13 @@ struct PreparedShortInfoUserpic {
[[nodiscard]] object_ptr PrepareShortInfoBox(
not_null peer,
Fn open,
- Fn videoPaused);
+ Fn videoPaused,
+ const style::ShortInfoBox *stOverride = nullptr);
[[nodiscard]] object_ptr PrepareShortInfoBox(
not_null peer,
- not_null navigation);
+ not_null navigation,
+ const style::ShortInfoBox *stOverride = nullptr);
[[nodiscard]] rpl::producer PrepareShortInfoStatus(
not_null peer);
diff --git a/Telegram/SourceFiles/boxes/premium_limits_box.cpp b/Telegram/SourceFiles/boxes/premium_limits_box.cpp
index 55fbe0a35..3fbdc34c1 100644
--- a/Telegram/SourceFiles/boxes/premium_limits_box.cpp
+++ b/Telegram/SourceFiles/boxes/premium_limits_box.cpp
@@ -404,6 +404,7 @@ std::unique_ptr PublicsController::createRow(
void SimpleLimitBox(
not_null box,
+ const style::PremiumLimits *stOverride,
not_null session,
bool premiumPossible,
rpl::producer title,
@@ -411,6 +412,8 @@ void SimpleLimitBox(
const QString &refAddition,
const InfographicDescriptor &descriptor,
bool fixed = false) {
+ const auto &st = stOverride ? *stOverride : st::defaultPremiumLimits;
+
box->setWidth(st::boxWideWidth);
const auto top = fixed
@@ -431,6 +434,7 @@ void SimpleLimitBox(
if (premiumPossible) {
Ui::Premium::AddLimitRow(
top,
+ st,
descriptor.premiumLimit,
descriptor.phrase,
0,
@@ -473,6 +477,7 @@ void SimpleLimitBox(
void SimpleLimitBox(
not_null box,
+ const style::PremiumLimits *stOverride,
not_null session,
rpl::producer title,
rpl::producer text,
@@ -481,6 +486,7 @@ void SimpleLimitBox(
bool fixed = false) {
SimpleLimitBox(
box,
+ stOverride,
session,
session->premiumPossible(),
std::move(title),
@@ -524,6 +530,7 @@ void SimplePinsLimitBox(
});
SimpleLimitBox(
box,
+ nullptr,
session,
tr::lng_filter_pin_limit_title(),
std::move(text),
@@ -561,6 +568,7 @@ void ChannelsLimitBox(
SimpleLimitBox(
box,
+ nullptr,
session,
tr::lng_channels_limit_title(),
std::move(text),
@@ -650,6 +658,7 @@ void PublicLinksLimitBox(
SimpleLimitBox(
box,
+ nullptr,
session,
tr::lng_links_limit_title(),
std::move(text),
@@ -716,6 +725,7 @@ void FilterChatsLimitBox(
SimpleLimitBox(
box,
+ nullptr,
session,
tr::lng_filter_chats_limit_title(),
std::move(text),
@@ -753,6 +763,7 @@ void FilterLinksLimitBox(
SimpleLimitBox(
box,
+ nullptr,
session,
tr::lng_filter_links_limit_title(),
std::move(text),
@@ -798,6 +809,7 @@ void FiltersLimitBox(
});
SimpleLimitBox(
box,
+ nullptr,
session,
tr::lng_filters_limit_title(),
std::move(text),
@@ -836,6 +848,7 @@ void ShareableFiltersLimitBox(
});
SimpleLimitBox(
box,
+ nullptr,
session,
tr::lng_filter_shared_limit_title(),
std::move(text),
@@ -900,6 +913,7 @@ void ForumPinsLimitBox(
Ui::Text::RichLangValue);
SimpleLimitBox(
box,
+ nullptr,
&forum->session(),
false,
tr::lng_filter_pin_limit_title(),
@@ -911,7 +925,8 @@ void ForumPinsLimitBox(
void CaptionLimitBox(
not_null box,
not_null session,
- int remove) {
+ int remove,
+ const style::PremiumLimits *stOverride) {
const auto premium = session->premium();
const auto premiumPossible = session->premiumPossible();
@@ -943,6 +958,7 @@ void CaptionLimitBox(
SimpleLimitBox(
box,
+ stOverride,
session,
tr::lng_caption_limit_title(),
std::move(text),
@@ -953,15 +969,17 @@ void CaptionLimitBox(
void CaptionLimitReachedBox(
not_null box,
not_null session,
- int remove) {
+ int remove,
+ const style::PremiumLimits *stOverride) {
Ui::ConfirmBox(box, Ui::ConfirmBoxArgs{
.text = tr::lng_caption_limit_reached(tr::now, lt_count, remove),
+ .labelStyle = stOverride ? &stOverride->boxLabel : nullptr,
.inform = true,
});
if (!session->premium()) {
box->addLeftButton(tr::lng_limits_increase(), [=] {
box->getDelegate()->showBox(
- Box(CaptionLimitBox, session, remove),
+ Box(CaptionLimitBox, session, remove, stOverride),
Ui::LayerOption::KeepOther,
anim::type::normal);
box->closeBox();
@@ -972,7 +990,8 @@ void CaptionLimitReachedBox(
void FileSizeLimitBox(
not_null box,
not_null session,
- uint64 fileSizeBytes) {
+ uint64 fileSizeBytes,
+ const style::PremiumLimits *stOverride) {
const auto limits = Data::PremiumLimits(session);
const auto defaultLimit = float64(limits.uploadMaxDefault());
const auto premiumLimit = float64(limits.uploadMaxPremium());
@@ -1011,6 +1030,7 @@ void FileSizeLimitBox(
SimpleLimitBox(
box,
+ stOverride,
session,
premiumPossible,
tr::lng_file_size_limit_title(),
@@ -1084,6 +1104,7 @@ void AccountsLimitBox(
if (premiumPossible) {
Ui::Premium::AddLimitRow(
top,
+ st::defaultPremiumLimits,
(QString::number(std::max(current, defaultLimit) + 1)
+ ((current + 1 == premiumLimit) ? "" : "+")),
QString::number(defaultLimit));
diff --git a/Telegram/SourceFiles/boxes/premium_limits_box.h b/Telegram/SourceFiles/boxes/premium_limits_box.h
index 55be7e40f..bb9115a3e 100644
--- a/Telegram/SourceFiles/boxes/premium_limits_box.h
+++ b/Telegram/SourceFiles/boxes/premium_limits_box.h
@@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/layers/generic_box.h"
+namespace style {
+struct PremiumLimits;
+} // namespace style
+
namespace Data {
class Forum;
} // namespace Data
@@ -57,15 +61,18 @@ void ForumPinsLimitBox(
void CaptionLimitBox(
not_null box,
not_null session,
- int remove);
+ int remove,
+ const style::PremiumLimits *stOverride = nullptr);
void CaptionLimitReachedBox(
not_null box,
not_null session,
- int remove);
+ int remove,
+ const style::PremiumLimits *stOverride = nullptr);
void FileSizeLimitBox(
not_null box,
not_null session,
- uint64 fileSizeBytes);
+ uint64 fileSizeBytes,
+ const style::PremiumLimits *stOverride = nullptr);
void AccountsLimitBox(
not_null box,
not_null session);
diff --git a/Telegram/SourceFiles/boxes/premium_preview_box.cpp b/Telegram/SourceFiles/boxes/premium_preview_box.cpp
index ffc5bc709..20581a726 100644
--- a/Telegram/SourceFiles/boxes/premium_preview_box.cpp
+++ b/Telegram/SourceFiles/boxes/premium_preview_box.cpp
@@ -76,7 +76,7 @@ bool operator==(const Descriptor &a, const Descriptor &b) {
struct Preload {
Descriptor descriptor;
std::shared_ptr media;
- base::weak_ptr controller;
+ std::weak_ptr show;
};
[[nodiscard]] std::vector &Preloads() {
@@ -168,7 +168,7 @@ void PreloadSticker(const std::shared_ptr &media) {
[[nodiscard]] not_null StickerPreview(
not_null parent,
- not_null controller,
+ std::shared_ptr show,
const std::shared_ptr &media,
Fn readyCallback = nullptr) {
using namespace HistoryView;
@@ -194,6 +194,8 @@ void PreloadSticker(const std::shared_ptr &media) {
struct State {
std::unique_ptr lottie;
std::unique_ptr effect;
+ style::owned_color pathFg = style::owned_color(
+ QColor(255, 255, 255, 64));
std::unique_ptr pathGradient;
bool readyInvoked = false;
};
@@ -239,15 +241,17 @@ void PreloadSticker(const std::shared_ptr &media) {
};
createLottieIfReady();
if (!state->lottie || !state->effect) {
- controller->session().downloaderTaskFinished(
+ show->session().downloaderTaskFinished(
) | rpl::take_while([=] {
createLottieIfReady();
return !state->lottie || !state->effect;
}) | rpl::start(result->lifetime());
}
- state->pathGradient = MakePathShiftGradient(
- controller->chatStyle(),
- [=] { result->update(); });
+ state->pathGradient = std::make_unique(
+ st::shadowFg,
+ state->pathFg.color(),
+ [=] { result->update(); },
+ rpl::never<>());
result->paintRequest(
) | rpl::start_with_next([=] {
@@ -262,7 +266,7 @@ void PreloadSticker(const std::shared_ptr &media) {
if (!state->lottie
|| !state->lottie->ready()
|| !state->effect->ready()) {
- p.setBrush(controller->chatStyle()->msgServiceBg());
+ p.setBrush(st::shadowFg);
ChatHelpers::PaintStickerThumbnailPath(
p,
media.get(),
@@ -302,7 +306,7 @@ void PreloadSticker(const std::shared_ptr &media) {
[[nodiscard]] not_null StickersPreview(
not_null parent,
- not_null controller,
+ std::shared_ptr show,
Fn readyCallback) {
const auto result = Ui::CreateChild(parent.get());
result->show();
@@ -327,7 +331,7 @@ void PreloadSticker(const std::shared_ptr &media) {
bool nextReady = false;
int index = 0;
};
- const auto premium = &controller->session().api().premium();
+ const auto premium = &show->session().api().premium();
const auto state = lifetime.make_state();
const auto create = [=](std::shared_ptr media) {
const auto outer = Ui::CreateChild(result);
@@ -340,7 +344,7 @@ void PreloadSticker(const std::shared_ptr &media) {
[[maybe_unused]] const auto sticker = StickerPreview(
outer,
- controller,
+ show,
media,
state->singleReadyCallback);
@@ -520,7 +524,7 @@ struct VideoPreviewDocument {
[[nodiscard]] not_null VideoPreview(
not_null parent,
- not_null controller,
+ std::shared_ptr show,
not_null document,
bool alignToBottom,
Fn readyCallback) {
@@ -683,7 +687,7 @@ struct VideoPreviewDocument {
[[nodiscard]] not_null GenericPreview(
not_null parent,
- not_null controller,
+ std::shared_ptr show,
PremiumPreview section,
Fn readyCallback) {
const auto result = Ui::CreateChild(parent.get());
@@ -699,7 +703,7 @@ struct VideoPreviewDocument {
std::vector> medias;
Ui::RpWidget *single = nullptr;
};
- const auto session = &controller->session();
+ const auto session = &show->session();
const auto state = lifetime.make_state();
const auto create = [=] {
const auto document = LookupVideo(session, section);
@@ -708,7 +712,7 @@ struct VideoPreviewDocument {
}
state->single = VideoPreview(
result,
- controller,
+ show,
document,
!VideoAlignToTop(section),
readyCallback);
@@ -724,14 +728,18 @@ struct VideoPreviewDocument {
[[nodiscard]] not_null GenerateDefaultPreview(
not_null parent,
- not_null controller,
+ std::shared_ptr show,
PremiumPreview section,
Fn readyCallback) {
switch (section) {
case PremiumPreview::Stickers:
- return StickersPreview(parent, controller, readyCallback);
+ return StickersPreview(parent, std::move(show), readyCallback);
default:
- return GenericPreview(parent, controller, section, readyCallback);
+ return GenericPreview(
+ parent,
+ std::move(show),
+ section,
+ readyCallback);
}
}
@@ -792,7 +800,7 @@ struct VideoPreviewDocument {
void PreviewBox(
not_null