diff --git a/.github/workflows/no-response.yml b/.github/workflows/cant-reproduce.yml
similarity index 57%
rename from .github/workflows/no-response.yml
rename to .github/workflows/cant-reproduce.yml
index f414a55fd..5c4edcba0 100644
--- a/.github/workflows/no-response.yml
+++ b/.github/workflows/cant-reproduce.yml
@@ -1,32 +1,11 @@
-name: No Response
+name: Can't reproduce.
-# Both `issue_comment` and `scheduled` event types are required for this Action
-# to work properly.
on:
- issue_comment:
- types: [created]
schedule:
- - cron: '0 0 * * *'
+ - cron: '0 3 * * *'
jobs:
- waiting-for-answer:
- runs-on: ubuntu-latest
- steps:
- - uses: lee-dohm/no-response@v0.5.0
- with:
- token: ${{ github.token }}
- responseRequiredLabel: waiting for answer
-
- needs-user-action:
- runs-on: ubuntu-latest
- steps:
- - uses: lee-dohm/no-response@v0.5.0
- with:
- token: ${{ github.token }}
- responseRequiredLabel: needs user action
-
cant-reproduce:
- if: github.event_name != 'issue_comment'
runs-on: ubuntu-latest
steps:
- uses: lee-dohm/no-response@v0.5.0
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 4eaf2ec22..8020e46c5 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -49,7 +49,6 @@ jobs:
defines:
- ""
- "DESKTOP_APP_DISABLE_X11_INTEGRATION"
- - "DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION"
env:
UPLOAD_ARTIFACT: "true"
diff --git a/.github/workflows/mac_packaged.yml b/.github/workflows/mac_packaged.yml
index 8ed4ffca1..d04b284de 100644
--- a/.github/workflows/mac_packaged.yml
+++ b/.github/workflows/mac_packaged.yml
@@ -49,7 +49,7 @@ jobs:
env:
GIT: "https://github.com"
- OPENALDIR: "/usr/local/opt/openal-soft"
+ CMAKE_PREFIX_PATH: "/usr/local/opt/ffmpeg@6:/usr/local/opt/openal-soft"
UPLOAD_ARTIFACT: "true"
ONLY_CACHE: "false"
MANUAL_CACHING: "1"
@@ -69,7 +69,7 @@ jobs:
run: |
brew update
brew upgrade || true
- brew install autoconf automake boost cmake ffmpeg openal-soft openssl opus ninja pkg-config python qt yasm xz
+ brew install autoconf automake boost cmake ffmpeg@6 openal-soft openssl opus ninja pkg-config python qt yasm xz
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
xcodebuild -version > CACHE_KEY.txt
diff --git a/.github/workflows/needs-user-action.yml b/.github/workflows/needs-user-action.yml
new file mode 100644
index 000000000..46ad9f87d
--- /dev/null
+++ b/.github/workflows/needs-user-action.yml
@@ -0,0 +1,16 @@
+name: Needs user action.
+
+on:
+ issue_comment:
+ types: [created]
+ schedule:
+ - cron: '0 2 * * *'
+
+jobs:
+ needs-user-action:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: lee-dohm/no-response@v0.5.0
+ with:
+ token: ${{ github.token }}
+ responseRequiredLabel: needs user action
diff --git a/.github/workflows/snap.yml b/.github/workflows/snap.yml
index 0c2bc4148..badcf6cc9 100644
--- a/.github/workflows/snap.yml
+++ b/.github/workflows/snap.yml
@@ -64,7 +64,7 @@ jobs:
uses: jlumbroso/free-disk-space@f68fdb76e2ea636224182cfb7377ff9a1708f9b8
- name: Telegram Desktop snap build.
- run: sg lxd -c 'snap run snapcraft -v'
+ run: sg lxd -c 'snap run snapcraft --verbosity=debug'
- name: Move artifact.
if: env.UPLOAD_ARTIFACT == 'true'
diff --git a/.github/workflows/waiting-for-answer.yml b/.github/workflows/waiting-for-answer.yml
new file mode 100644
index 000000000..5e5ff87c9
--- /dev/null
+++ b/.github/workflows/waiting-for-answer.yml
@@ -0,0 +1,16 @@
+name: Waiting for answer.
+
+on:
+ issue_comment:
+ types: [created]
+ schedule:
+ - cron: '30 0 * * *'
+
+jobs:
+ waiting-for-answer:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: lee-dohm/no-response@v0.5.0
+ with:
+ token: ${{ github.token }}
+ responseRequiredLabel: waiting for answer
diff --git a/.gitmodules b/.gitmodules
index 64928f01b..a2a91a3f1 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -82,12 +82,6 @@
[submodule "Telegram/ThirdParty/dispatch"]
path = Telegram/ThirdParty/dispatch
url = https://github.com/apple/swift-corelibs-libdispatch
-[submodule "Telegram/ThirdParty/plasma-wayland-protocols"]
- path = Telegram/ThirdParty/plasma-wayland-protocols
- url = https://github.com/KDE/plasma-wayland-protocols.git
-[submodule "Telegram/ThirdParty/wayland-protocols"]
- path = Telegram/ThirdParty/wayland-protocols
- url = https://github.com/gitlab-freedesktop-mirrors/wayland-protocols.git
[submodule "Telegram/ThirdParty/kimageformats"]
path = Telegram/ThirdParty/kimageformats
url = https://github.com/KDE/kimageformats.git
@@ -97,9 +91,6 @@
[submodule "Telegram/ThirdParty/cld3"]
path = Telegram/ThirdParty/cld3
url = https://github.com/google/cld3.git
-[submodule "Telegram/ThirdParty/wayland"]
- path = Telegram/ThirdParty/wayland
- url = https://github.com/gitlab-freedesktop-mirrors/wayland.git
[submodule "Telegram/ThirdParty/libprisma"]
path = Telegram/ThirdParty/libprisma
url = https://github.com/desktop-app/libprisma.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6971dbc8d..b4c265e24 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -62,7 +62,7 @@ if (NOT DESKTOP_APP_USE_PACKAGED)
if (WIN32)
set(qt_version 5.15.13)
elseif (APPLE)
- set(qt_version 6.2.7)
+ set(qt_version 6.2.8)
endif()
endif()
include(cmake/external/qt/package.cmake)
diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index 536fafb0b..11f1fc9a3 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -342,6 +342,8 @@ PRIVATE
boxes/local_storage_box.h
boxes/max_invite_box.cpp
boxes/max_invite_box.h
+ boxes/moderate_messages_box.cpp
+ boxes/moderate_messages_box.h
boxes/peer_list_box.cpp
boxes/peer_list_box.h
boxes/peer_list_controllers.cpp
@@ -529,10 +531,14 @@ PRIVATE
data/business/data_business_info.h
data/business/data_shortcut_messages.cpp
data/business/data_shortcut_messages.h
+ data/components/recent_peers.cpp
+ data/components/recent_peers.h
data/components/scheduled_messages.cpp
data/components/scheduled_messages.h
data/components/sponsored_messages.cpp
data/components/sponsored_messages.h
+ data/components/top_peers.cpp
+ data/components/top_peers.h
data/notify/data_notify_settings.cpp
data/notify/data_notify_settings.h
data/notify/data_peer_notify_settings.cpp
@@ -677,6 +683,18 @@ PRIVATE
data/data_wall_paper.h
data/data_web_page.cpp
data/data_web_page.h
+ dialogs/ui/dialogs_layout.cpp
+ 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_suggestions.cpp
+ dialogs/ui/dialogs_suggestions.h
+ dialogs/ui/dialogs_topics_view.cpp
+ dialogs/ui/dialogs_topics_view.h
+ dialogs/ui/dialogs_video_userpic.cpp
+ dialogs/ui/dialogs_video_userpic.h
dialogs/dialogs_entry.cpp
dialogs/dialogs_entry.h
dialogs/dialogs_indexed_list.cpp
@@ -699,16 +717,6 @@ PRIVATE
dialogs/dialogs_search_tags.h
dialogs/dialogs_widget.cpp
dialogs/dialogs_widget.h
- dialogs/ui/dialogs_layout.cpp
- 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
- dialogs/ui/dialogs_video_userpic.h
editor/color_picker.cpp
editor/color_picker.h
editor/controllers/controllers.h
@@ -1268,11 +1276,6 @@ PRIVATE
payments/payments_checkout_process.h
payments/payments_form.cpp
payments/payments_form.h
- platform/linux/linux_wayland_integration_dummy.cpp
- platform/linux/linux_wayland_integration.cpp
- platform/linux/linux_wayland_integration.h
- platform/linux/linux_xdp_open_with_dialog.cpp
- platform/linux/linux_xdp_open_with_dialog.h
platform/linux/file_utilities_linux.cpp
platform/linux/file_utilities_linux.h
platform/linux/launcher_linux.cpp
@@ -1625,16 +1628,6 @@ if (NOT build_winstore)
)
endif()
-if (DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
- remove_target_sources(Telegram ${src_loc}
- platform/linux/linux_wayland_integration.cpp
- )
-else()
- remove_target_sources(Telegram ${src_loc}
- platform/linux/linux_wayland_integration_dummy.cpp
- )
-endif()
-
if (DESKTOP_APP_USE_PACKAGED)
remove_target_sources(Telegram ${src_loc}
platform/mac/mac_iconv_helper.c
@@ -1774,19 +1767,6 @@ else()
desktop-app::external_xcb
)
endif()
-
- if (NOT DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
- qt_generate_wayland_protocol_client_sources(Telegram
- FILES
- ${third_party_loc}/wayland/protocol/wayland.xml
- ${third_party_loc}/plasma-wayland-protocols/src/protocols/plasma-shell.xml
- )
-
- target_link_libraries(Telegram
- PRIVATE
- desktop-app::external_wayland_client
- )
- endif()
endif()
if (build_macstore)
diff --git a/Telegram/Resources/animations/noresults.tgs b/Telegram/Resources/animations/noresults.tgs
new file mode 100644
index 000000000..62a21279f
Binary files /dev/null and b/Telegram/Resources/animations/noresults.tgs differ
diff --git a/Telegram/Resources/animations/search.tgs b/Telegram/Resources/animations/search.tgs
new file mode 100644
index 000000000..db635fb57
Binary files /dev/null and b/Telegram/Resources/animations/search.tgs differ
diff --git a/Telegram/Resources/icons/chat/live_location_long.png b/Telegram/Resources/icons/chat/live_location_long.png
new file mode 100644
index 000000000..847930f54
Binary files /dev/null and b/Telegram/Resources/icons/chat/live_location_long.png differ
diff --git a/Telegram/Resources/icons/chat/live_location_long@2x.png b/Telegram/Resources/icons/chat/live_location_long@2x.png
new file mode 100644
index 000000000..d4c018200
Binary files /dev/null and b/Telegram/Resources/icons/chat/live_location_long@2x.png differ
diff --git a/Telegram/Resources/icons/chat/live_location_long@3x.png b/Telegram/Resources/icons/chat/live_location_long@3x.png
new file mode 100644
index 000000000..3a8cd36b5
Binary files /dev/null and b/Telegram/Resources/icons/chat/live_location_long@3x.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_pinned_shadow.png b/Telegram/Resources/icons/dialogs/dialogs_pinned_shadow.png
new file mode 100644
index 000000000..19f8e0b15
Binary files /dev/null and b/Telegram/Resources/icons/dialogs/dialogs_pinned_shadow.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_pinned_shadow@2x.png b/Telegram/Resources/icons/dialogs/dialogs_pinned_shadow@2x.png
new file mode 100644
index 000000000..ac695b71d
Binary files /dev/null and b/Telegram/Resources/icons/dialogs/dialogs_pinned_shadow@2x.png differ
diff --git a/Telegram/Resources/icons/dialogs/dialogs_pinned_shadow@3x.png b/Telegram/Resources/icons/dialogs/dialogs_pinned_shadow@3x.png
new file mode 100644
index 000000000..b05f0f35f
Binary files /dev/null and b/Telegram/Resources/icons/dialogs/dialogs_pinned_shadow@3x.png differ
diff --git a/Telegram/Resources/icons/menu/fonts.png b/Telegram/Resources/icons/menu/fonts.png
new file mode 100644
index 000000000..a82aa2166
Binary files /dev/null and b/Telegram/Resources/icons/menu/fonts.png differ
diff --git a/Telegram/Resources/icons/menu/fonts@2x.png b/Telegram/Resources/icons/menu/fonts@2x.png
new file mode 100644
index 000000000..5d735d58b
Binary files /dev/null and b/Telegram/Resources/icons/menu/fonts@2x.png differ
diff --git a/Telegram/Resources/icons/menu/fonts@3x.png b/Telegram/Resources/icons/menu/fonts@3x.png
new file mode 100644
index 000000000..0aa3679f3
Binary files /dev/null and b/Telegram/Resources/icons/menu/fonts@3x.png differ
diff --git a/Telegram/Resources/iv_html/page.css b/Telegram/Resources/iv_html/page.css
index 2763760f2..9c0ab832f 100644
--- a/Telegram/Resources/iv_html/page.css
+++ b/Telegram/Resources/iv_html/page.css
@@ -134,9 +134,32 @@ html.custom_scroll ::-webkit-scrollbar-thumb:hover {
.page-slide {
position: relative;
width: 100%;
+ min-height: 100%;
margin-left: 0%;
transition: margin 240ms ease-in-out;
}
+.page-footer {
+ height: 32px;
+ margin-top: -32px;
+ background: var(--td-window-bg-over);
+}
+.page-footer .content {
+ padding: 3px 18px;
+ font-size: 15px;
+ color: var(--td-window-sub-text-fg);
+ text-align: center;
+}
+.page-footer .wrong {
+ position: relative;
+ padding: 5px;
+ margin: -5px;
+ color: var(--td-window-sub-text-fg);
+ text-decoration: none;
+ cursor: pointer;
+}
+.page-footer .wrong:hover {
+ text-decoration: underline;
+}
.hidden-left,
.hidden-right {
pointer-events: none;
@@ -148,7 +171,7 @@ html.custom_scroll ::-webkit-scrollbar-thumb:hover {
margin-left: 100%;
}
article {
- padding-bottom: 12px;
+ padding-bottom: 40px;
overflow-y: hidden;
overflow-x: auto;
white-space: pre-wrap;
@@ -893,6 +916,9 @@ section.related a.related-link:after {
right: 0;
bottom: 0;
}
+section.related a.related-link:last-child:after {
+ border-bottom: 0px;
+}
section.related .related-link-url {
display: block;
font-size: 15px;
@@ -1027,6 +1053,9 @@ section.channel > a > h4 {
display: block;
margin: 0 auto;
}
+.media-outer {
+ margin-bottom: 16px;
+}
.photo-wrap,
.video-wrap {
width: 100%;
diff --git a/Telegram/Resources/iv_html/page.js b/Telegram/Resources/iv_html/page.js
index 053a6a0ab..bae02fe48 100644
--- a/Telegram/Resources/iv_html/page.js
+++ b/Telegram/Resources/iv_html/page.js
@@ -26,7 +26,7 @@ var IV = {
}
target = target.parentNode;
}
- if (!target || !target.hasAttribute('href')) {
+ if (!target || (context === '' && !target.hasAttribute('href'))) {
return;
}
var base = document.createElement('A');
@@ -413,9 +413,12 @@ var IV = {
var article = function (el) {
return el.getElementsByTagName('article')[0];
};
- var from = article(IV.findPageScroll());
- var to = article(IV.makeScrolledContent(data.html));
- morphdom(from, to, {
+ var footer = function (el) {
+ return el.getElementsByClassName('page-footer')[0];
+ };
+ var from = IV.findPageScroll();
+ var to = IV.makeScrolledContent(data.html);
+ morphdom(article(from), article(to), {
onBeforeElUpdated: function (fromEl, toEl) {
if (fromEl.classList.contains('video')
&& toEl.classList.contains('video')
@@ -439,6 +442,7 @@ var IV = {
return !fromEl.isEqualNode(toEl);
}
});
+ morphdom(footer(from), footer(to));
IV.initMedia();
eval(data.js);
},
@@ -477,9 +481,7 @@ var IV = {
var result = document.createElement('div');
result.className = 'page-scroll';
result.tabIndex = '-1';
- result.innerHTML = '
';
+ result.innerHTML = html.trim();
result.onscroll = IV.frameScrolled;
return result;
},
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 2c2009edd..34e5cfaed 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -730,6 +730,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_angle_backend_d3d11on12" = "D3D11on12";
"lng_settings_angle_backend_opengl" = "OpenGL";
"lng_settings_angle_backend_disabled" = "Disabled";
+"lng_settings_top_peers_title" = "Frequent contacts";
+"lng_settings_top_peers_suggest" = "Suggest frequent contacts";
+"lng_settings_top_peers_about" = "Display people you message frequently at the top of the search section for quick access.";
"lng_settings_sensitive_title" = "Sensitive content";
"lng_settings_sensitive_disable_filtering" = "Disable filtering";
"lng_settings_sensitive_about" = "Display sensitive media in public channels on all your Telegram devices.";
@@ -840,6 +843,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_auto_night_mode_on" = "System";
"lng_settings_auto_night_warning" = "You have enabled auto-night mode. If you want to change the dark mode settings, you'll need to disable it first.";
"lng_settings_auto_night_disable" = "Disable";
+"lng_settings_font_family" = "Font family";
"lng_settings_color_title" = "Color preview";
"lng_settings_color_reply" = "Reply to your message";
@@ -1492,6 +1496,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_reactions_none_about" = "Members of the group can't add any reactions to messages.";
"lng_manage_peer_reactions_some_title" = "Only allow these reactions";
"lng_manage_peer_reactions_available" = "Available reactions";
+"lng_manage_peer_reactions_available_ph" = "Add reactions...";
"lng_manage_peer_reactions_own" = "You can also {link} emoji packs and use them as reactions.";
"lng_manage_peer_reactions_own_link" = "create your own";
"lng_manage_peer_reactions_level#one" = "Your channel needs to reach level **{count}** to use **{same_count}** custom reaction.";
@@ -1500,6 +1505,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_reactions_boost_link" = "here";
"lng_manage_peer_reactions_limit" = "Channels can't have more custom reactions.";
+"lng_manage_peer_reactions_max_title" = "Maximum number of reactions";
+"lng_manage_peer_reactions_max_slider#one" = "{count} reaction per post";
+"lng_manage_peer_reactions_max_slider#other" = "{count} reactions per post";
+"lng_manage_peer_reactions_max_about" = "Limit the number of different reactions that can be added to a post, including already published ones.";
+
"lng_manage_peer_antispam" = "Aggressive Anti-Spam";
"lng_manage_peer_antispam_about" = "Telegram will filter more spam but may occasionally affect ordinary messages. You can report False Positives in Recent Actions.";
"lng_manage_peer_antispam_not_enough#one" = "Aggressive filtering can be enabled only in groups with more than **{count} member**.";
@@ -2269,6 +2279,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_business_about_chat_intro" = "Customize the message people see before they start a chat with you.";
"lng_business_subtitle_chat_links" = "Links to Chat";
"lng_business_about_chat_links" = "Create links that start a chat with you, suggesting the first message.";
+"lng_business_subtitle_sponsored" = "Ads in Channels";
+"lng_business_button_sponsored" = "Do Not Hide Ads";
+"lng_business_about_sponsored" = "As a Premium subscriber, you don’t see any ads on Telegram, but you can turn them on, for example, to view your own ads that you launched on the {link}";
+"lng_business_about_sponsored_link" = "Telegram Ad Platform {emoji}";
+"lng_business_about_sponsored_url" = "https://ads.telegram.org";
"lng_location_title" = "Location";
"lng_location_about" = "Display the location of your business on your account.";
@@ -2839,7 +2854,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_in_dlg_audio_count#other" = "{count} audio";
"lng_ban_user" = "Ban User";
+"lng_ban_users" = "Ban users";
+"lng_restrict_users" = "Restrict users";
"lng_delete_all_from_user" = "Delete all from {user}";
+"lng_delete_all_from_users" = "Delete all from users";
+"lng_restrict_user_part" = "Partially restrict this user {emoji}";
+"lng_restrict_users_part" = "Partially restrict users {emoji}";
+"lng_restrict_user_full" = "Fully ban this user {emoji}";
+"lng_restrict_users_full" = "Fully ban users {emoji}";
+"lng_restrict_users_part_single_header" = "What can this user do?";
+"lng_restrict_users_part_header#one" = "What can {count} selected user do?";
+"lng_restrict_users_part_header#other" = "What can {count} selected users do?";
"lng_report_spam" = "Report Spam";
"lng_report_spam_and_leave" = "Report spam and leave";
"lng_report_spam_done" = "Thank you for your report.";
@@ -3067,6 +3092,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_unread_bar_some" = "Unread messages";
"lng_maps_point" = "Location";
+"lng_live_location" = "Live Location";
+"lng_live_location_now" = "updated just now";
+"lng_live_location_minutes#one" = "updated {count} minute ago";
+"lng_live_location_minutes#other" = "updated {count} minutes ago";
+"lng_live_location_hours#one" = "updated {count} hour ago";
+"lng_live_location_hours#other" = "updated {count} hours ago";
+"lng_live_location_today" = "updated today at {time}";
+"lng_live_location_yesterday" = "updated yesterday at {time}";
+"lng_live_location_date_time" = "updated {date} at {time}";
"lng_save_photo" = "Save image";
"lng_save_video" = "Save video";
"lng_save_audio_file" = "Save audio file";
@@ -3410,6 +3444,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_mediaview_forward" = "Forward";
"lng_mediaview_delete" = "Delete";
"lng_mediaview_save_to_profile" = "Save to Profile";
+"lng_mediaview_pin_story_done" = "Story pinned";
+"lng_mediaview_pin_story_about" = "Now it will be always shown on the top.";
+"lng_mediaview_pin_stories_done#one" = "{count} story pinned";
+"lng_mediaview_pin_stories_done#other" = "{count} stories pinned";
+"lng_mediaview_pin_stories_about#one" = "Now it will be always shown on the top.";
+"lng_mediaview_pin_stories_about#other" = "Now they will be always shown on the top.";
+"lng_mediaview_unpin_story_done" = "Story unpinned.";
+"lng_mediaview_unpin_stories_done#one" = "{count} story unpinned";
+"lng_mediaview_unpin_stories_done#other" = "{count} stories unpinned";
+"lng_mediaview_pin_limit#one" = "You can't pin more than {count} story.";
+"lng_mediaview_pin_limit#other" = "You can't pin more than {count} stories.";
"lng_mediaview_archive_story" = "Archive Story";
"lng_mediaview_photos_all" = "View all photos";
"lng_mediaview_files_all" = "View all files";
@@ -4704,6 +4749,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_view_button_boost" = "Boost";
"lng_view_button_giftcode" = "Open";
"lng_view_button_iv" = "Instant View";
+"lng_view_button_stickerset" = "View stickers";
+"lng_view_button_emojipack" = "View emoji";
"lng_sponsored_hide_ads" = "Hide";
"lng_sponsored_title" = "What are sponsored messages?";
@@ -5073,6 +5120,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_iv_share" = "Share";
"lng_iv_join_channel" = "Join";
"lng_iv_window_title" = "Instant View";
+"lng_iv_wrong_layout" = "Wrong layout?";
"lng_limit_download_title" = "Download speed limited";
"lng_limit_download_subscribe" = "Subscribe to {link} and increase download speed {increase}.";
@@ -5087,6 +5135,32 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_limit_upload_increase_speed" = "by **{percent}**";
"lng_limit_upload_subscribe_link" = "Telegram Premium";
+"lng_recent_frequent" = "Frequent contacts";
+"lng_recent_frequent_all" = "Show all";
+"lng_recent_frequent_collapse" = "Collapse";
+"lng_recent_title" = "Recent";
+"lng_recent_clear" = "Clear";
+"lng_recent_clear_sure" = "Do you want to clear your search history?";
+"lng_recent_remove" = "Remove from Recent";
+"lng_recent_clear_all" = "Clear all";
+"lng_recent_hide_top" = "Remove all & Disable";
+"lng_recent_hide_sure" = "Are you sure you want to clear and disable frequent contacts list?\n\nYou can always turn this feature back on in Settings > Privacy > Suggest Frequent Contacts.";
+"lng_recent_hide_button" = "Hide";
+"lng_recent_none" = "Recent search results\nwill appear here.";
+"lng_recent_chats" = "Chats";
+"lng_recent_channels" = "Channels";
+"lng_channels_none_title" = "No channels yet...";
+"lng_channels_none_about" = "You are not currently subscribed to any channels.";
+"lng_channels_your_title" = "Channels you joined";
+"lng_channels_your_more" = "Show more";
+"lng_channels_your_less" = "Show less";
+"lng_channels_recommended" = "Recommended channels";
+
+"lng_font_box_title" = "Choose font family";
+"lng_font_default" = "Default";
+"lng_font_system" = "System font";
+"lng_font_not_found" = "Font not found.";
+
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose Default Program...";
diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc
index 5b72c461f..16920ae4d 100644
--- a/Telegram/Resources/qrc/telegram/animations.qrc
+++ b/Telegram/Resources/qrc/telegram/animations.qrc
@@ -24,5 +24,7 @@
../../animations/chat_link.tgs
../../animations/collectible_username.tgs
../../animations/collectible_phone.tgs
+ ../../animations/search.tgs
+ ../../animations/noresults.tgs
diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml
index 734a63bc4..0021dd5de 100644
--- a/Telegram/Resources/uwp/AppX/AppxManifest.xml
+++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml
@@ -10,7 +10,7 @@
+ Version="5.0.1.0" />
Telegram Desktop
Telegram Messenger LLP
diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc
index 481b83cfb..e7d2777da 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,16,8,0
- PRODUCTVERSION 4,16,8,0
+ FILEVERSION 5,0,1,0
+ PRODUCTVERSION 5,0,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
- VALUE "FileVersion", "4.16.8.0"
+ VALUE "FileVersion", "5.0.1.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "4.16.8.0"
+ VALUE "ProductVersion", "5.0.1.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc
index 208fdf399..d3e2f5f5b 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,16,8,0
- PRODUCTVERSION 4,16,8,0
+ FILEVERSION 5,0,1,0
+ PRODUCTVERSION 5,0,1,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.16.8.0"
+ VALUE "FileVersion", "5.0.1.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "4.16.8.0"
+ VALUE "ProductVersion", "5.0.1.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/SourceFiles/api/api_chat_participants.cpp b/Telegram/SourceFiles/api/api_chat_participants.cpp
index 745e0b883..a4cd0c367 100644
--- a/Telegram/SourceFiles/api/api_chat_participants.cpp
+++ b/Telegram/SourceFiles/api/api_chat_participants.cpp
@@ -212,7 +212,7 @@ void ApplyBotsList(
}
[[nodiscard]] ChatParticipants::Channels ParseSimilar(
- not_null channel,
+ not_null session,
const MTPmessages_Chats &chats) {
auto result = ChatParticipants::Channels();
std::vector>();
@@ -220,13 +220,13 @@ void ApplyBotsList(
const auto &list = data.vchats().v;
result.list.reserve(list.size());
for (const auto &chat : list) {
- const auto peer = channel->owner().processChat(chat);
+ const auto peer = session->data().processChat(chat);
if (const auto channel = peer->asChannel()) {
result.list.push_back(channel);
}
}
if constexpr (MTPDmessages_chatsSlice::Is()) {
- if (channel->session().premiumPossible()) {
+ if (session->premiumPossible()) {
result.more = data.vcount().v - data.vchats().v.size();
}
}
@@ -234,6 +234,12 @@ void ApplyBotsList(
return result;
}
+[[nodiscard]] ChatParticipants::Channels ParseSimilar(
+ not_null channel,
+ const MTPmessages_Chats &chats) {
+ return ParseSimilar(&channel->session(), chats);
+}
+
} // namespace
ChatParticipant::ChatParticipant(
@@ -351,7 +357,8 @@ QString ChatParticipant::rank() const {
}
ChatParticipants::ChatParticipants(not_null api)
-: _api(&api->instance()) {
+: _session(&api->session())
+, _api(&api->instance()) {
}
void ChatParticipants::requestForAdd(
@@ -585,6 +592,33 @@ ChatParticipants::Parsed ChatParticipants::ParseRecent(
return result;
}
+void ChatParticipants::Restrict(
+ not_null channel,
+ not_null participant,
+ ChatRestrictionsInfo oldRights,
+ ChatRestrictionsInfo newRights,
+ Fn onDone,
+ Fn onFail) {
+ channel->session().api().request(MTPchannels_EditBanned(
+ channel->inputChannel,
+ participant->input,
+ MTP_chatBannedRights(
+ MTP_flags(MTPDchatBannedRights::Flags::from_raw(
+ uint32(newRights.flags))),
+ MTP_int(newRights.until))
+ )).done([=](const MTPUpdates &result) {
+ channel->session().api().applyUpdates(result);
+ channel->applyEditBanned(participant, oldRights, newRights);
+ if (onDone) {
+ onDone();
+ }
+ }).fail([=] {
+ if (onFail) {
+ onFail();
+ }
+ }).send();
+}
+
void ChatParticipants::requestSelf(not_null channel) {
if (_selfParticipantRequests.contains(channel)) {
return;
@@ -730,8 +764,11 @@ void ChatParticipants::loadSimilarChannels(not_null channel) {
return;
}
}
+ using Flag = MTPchannels_GetChannelRecommendations::Flag;
_similar[channel].requestId = _api.request(
- MTPchannels_GetChannelRecommendations(channel->inputChannel)
+ MTPchannels_GetChannelRecommendations(
+ MTP_flags(Flag::f_channel),
+ channel->inputChannel)
).done([=](const MTPmessages_Chats &result) {
auto &similar = _similar[channel];
similar.requestId = 0;
@@ -766,4 +803,29 @@ auto ChatParticipants::similarLoaded() const
return _similarLoaded.events();
}
+void ChatParticipants::loadRecommendations() {
+ if (_recommendationsLoaded.current() || _recommendations.requestId) {
+ return;
+ }
+ _recommendations.requestId = _api.request(
+ MTPchannels_GetChannelRecommendations(
+ MTP_flags(0),
+ MTP_inputChannelEmpty())
+ ).done([=](const MTPmessages_Chats &result) {
+ _recommendations.requestId = 0;
+ auto parsed = ParseSimilar(_session, result);
+ _recommendations.channels = std::move(parsed);
+ _recommendations.channels.more = 0;
+ _recommendationsLoaded = true;
+ }).send();
+}
+
+const ChatParticipants::Channels &ChatParticipants::recommendations() const {
+ return _recommendations.channels;
+}
+
+rpl::producer<> ChatParticipants::recommendationsLoaded() const {
+ return _recommendationsLoaded.changes() | rpl::to_empty;
+}
+
} // namespace Api
diff --git a/Telegram/SourceFiles/api/api_chat_participants.h b/Telegram/SourceFiles/api/api_chat_participants.h
index b8fc9fc67..ad5aa930f 100644
--- a/Telegram/SourceFiles/api/api_chat_participants.h
+++ b/Telegram/SourceFiles/api/api_chat_participants.h
@@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class ApiWrap;
class ChannelData;
+namespace Main {
+class Session;
+} // namespace Main
+
namespace Ui {
class Show;
} // namespace Ui
@@ -96,6 +100,13 @@ public:
static Parsed ParseRecent(
not_null channel,
const TLMembers &data);
+ static void Restrict(
+ not_null channel,
+ not_null participant,
+ ChatRestrictionsInfo oldRights,
+ ChatRestrictionsInfo newRights,
+ Fn onDone,
+ Fn onFail);
void add(
std::shared_ptr show,
not_null peer,
@@ -134,12 +145,18 @@ public:
[[nodiscard]] auto similarLoaded() const
-> rpl::producer>;
+ void loadRecommendations();
+ [[nodiscard]] const Channels &recommendations() const;
+ [[nodiscard]] rpl::producer<> recommendationsLoaded() const;
+
private:
struct SimilarChannels {
Channels channels;
mtpRequestId requestId = 0;
};
+ const not_null _session;
+
MTP::Sender _api;
using PeerRequests = base::flat_map;
@@ -165,6 +182,9 @@ private:
base::flat_map, SimilarChannels> _similar;
rpl::event_stream> _similarLoaded;
+ SimilarChannels _recommendations;
+ rpl::variable _recommendationsLoaded = false;
+
};
} // namespace Api
diff --git a/Telegram/SourceFiles/api/api_confirm_phone.cpp b/Telegram/SourceFiles/api/api_confirm_phone.cpp
index 0dd1ae9a7..f4788e128 100644
--- a/Telegram/SourceFiles/api/api_confirm_phone.cpp
+++ b/Telegram/SourceFiles/api/api_confirm_phone.cpp
@@ -62,6 +62,10 @@ void ConfirmPhone::resolve(
return bad("FirebaseSms");
}, [&](const MTPDauth_sentCodeTypeEmailCode &) {
return bad("EmailCode");
+ }, [&](const MTPDauth_sentCodeTypeSmsWord &) {
+ return bad("SmsWord");
+ }, [&](const MTPDauth_sentCodeTypeSmsPhrase &) {
+ return bad("SmsPhrase");
}, [&](const MTPDauth_sentCodeTypeSetUpEmailRequired &) {
return bad("SetUpEmailRequired");
});
diff --git a/Telegram/SourceFiles/api/api_premium.cpp b/Telegram/SourceFiles/api/api_premium.cpp
index 5257feb2d..6ff4aa130 100644
--- a/Telegram/SourceFiles/api/api_premium.cpp
+++ b/Telegram/SourceFiles/api/api_premium.cpp
@@ -602,6 +602,41 @@ bool PremiumGiftCodeOptions::giveawayGiftsPurchaseAvailable() const {
false);
}
+SponsoredToggle::SponsoredToggle(not_null session)
+: _api(&session->api().instance()) {
+}
+
+rpl::producer SponsoredToggle::toggled() {
+ return [=](auto consumer) {
+ auto lifetime = rpl::lifetime();
+
+ _api.request(MTPusers_GetFullUser(
+ MTP_inputUserSelf()
+ )).done([=](const MTPusers_UserFull &result) {
+ consumer.put_next_copy(
+ result.data().vfull_user().data().is_sponsored_enabled());
+ }).fail([=] { consumer.put_next(false); }).send();
+
+ return lifetime;
+ };
+}
+
+rpl::producer SponsoredToggle::setToggled(bool v) {
+ return [=](auto consumer) {
+ auto lifetime = rpl::lifetime();
+
+ _api.request(MTPaccount_ToggleSponsoredMessages(
+ MTP_bool(v)
+ )).done([=] {
+ consumer.put_done();
+ }).fail([=](const MTP::Error &error) {
+ consumer.put_error_copy(error.type());
+ }).send();
+
+ return lifetime;
+ };
+}
+
RequirePremiumState ResolveRequiresPremiumToWrite(
not_null peer,
History *maybeHistory) {
diff --git a/Telegram/SourceFiles/api/api_premium.h b/Telegram/SourceFiles/api/api_premium.h
index 9bacca92d..83423fcd2 100644
--- a/Telegram/SourceFiles/api/api_premium.h
+++ b/Telegram/SourceFiles/api/api_premium.h
@@ -216,6 +216,18 @@ private:
};
+class SponsoredToggle final {
+public:
+ explicit SponsoredToggle(not_null session);
+
+ [[nodiscard]] rpl::producer toggled();
+ [[nodiscard]] rpl::producer setToggled(bool);
+
+private:
+ MTP::Sender _api;
+
+};
+
enum class RequirePremiumState {
Unknown,
Yes,
diff --git a/Telegram/SourceFiles/api/api_statistics.cpp b/Telegram/SourceFiles/api/api_statistics.cpp
index 7139c5ebb..ce1966623 100644
--- a/Telegram/SourceFiles/api/api_statistics.cpp
+++ b/Telegram/SourceFiles/api/api_statistics.cpp
@@ -760,14 +760,14 @@ rpl::producer EarnStatistics::request() {
channel()->inputChannel
)).done([=](const MTPstats_BroadcastRevenueStats &result) {
const auto &data = result.data();
-
+ const auto &balances = data.vbalances().data();
_data = Data::EarnStatistics{
.topHoursGraph = StatisticalGraphFromTL(
data.vtop_hours_graph()),
.revenueGraph = StatisticalGraphFromTL(data.vrevenue_graph()),
- .currentBalance = data.vcurrent_balance().v,
- .availableBalance = data.vavailable_balance().v,
- .overallRevenue = data.voverall_revenue().v,
+ .currentBalance = balances.vcurrent_balance().v,
+ .availableBalance = balances.vavailable_balance().v,
+ .overallRevenue = balances.voverall_revenue().v,
.usdRate = data.vusd_rate().v,
};
diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp
index 97b2f7529..8821bb245 100644
--- a/Telegram/SourceFiles/api/api_updates.cpp
+++ b/Telegram/SourceFiles/api/api_updates.cpp
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/mtproto_dc_options.h"
#include "data/business/data_shortcut_messages.h"
#include "data/components/scheduled_messages.h"
+#include "data/components/top_peers.h"
#include "data/notify/data_notify_settings.h"
#include "data/stickers/data_stickers.h"
#include "data/data_saved_messages.h"
@@ -1585,6 +1586,11 @@ void Updates::feedUpdate(const MTPUpdate &update) {
} else {
if (existing) {
existing->destroy();
+ } else {
+ // Not the server-side date, but close enough.
+ session().topPeers().increment(
+ local->history()->peer,
+ local->date());
}
local->setRealId(d.vid().v);
}
diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp
index a112c478a..828b2d095 100644
--- a/Telegram/SourceFiles/boxes/background_preview_box.cpp
+++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp
@@ -940,7 +940,7 @@ int BackgroundPreviewBox::textsTop() const {
- st::historyPaddingBottom
- (_service ? _service->height() : 0)
- _text1->height()
- - (forChannel() ? _text2->height() : 0);
+ - (forChannel() ? 0 : _text2->height());
}
QRect BackgroundPreviewBox::radialRect() const {
diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style
index c181168d1..87fa1556f 100644
--- a/Telegram/SourceFiles/boxes/boxes.style
+++ b/Telegram/SourceFiles/boxes/boxes.style
@@ -546,7 +546,7 @@ rightsToggle: Toggle(defaultToggle) {
vsize: 0px;
vshift: 1px;
stroke: 2px;
- duration: 120;
+ duration: universalDuration;
}
rightsButton: SettingsButton(defaultSettingsButton) {
@@ -691,6 +691,10 @@ createPollOptionField: InputField(createPollField) {
placeholderMargins: margins(2px, 0px, 2px, 0px);
heightMax: 68px;
}
+createPollOptionFieldPremium: InputField(createPollOptionField) {
+ textMargins: margins(22px, 11px, 68px, 11px);
+}
+createPollOptionFieldPremiumEmojiPosition: point(15px, -1px);
createPollSolutionField: InputField(createPollField) {
textMargins: margins(0px, 4px, 0px, 4px);
border: 1px;
@@ -704,7 +708,7 @@ createPollOptionRemove: CrossButton {
cross: CrossAnimation {
size: 22px;
skip: 6px;
- stroke: 1.;
+ stroke: 1.5;
minScale: 0.3;
}
crossFg: boxTitleCloseFg;
@@ -718,6 +722,7 @@ createPollOptionRemove: CrossButton {
}
}
createPollOptionRemovePosition: point(11px, 9px);
+createPollOptionEmojiPositionSkip: 4px;
createPollWarning: FlatLabel(defaultFlatLabel) {
textFg: windowSubTextFg;
palette: TextPalette(defaultTextPalette) {
@@ -1074,3 +1079,23 @@ collectibleBox: Box(defaultBox) {
buttonHeight: 36px;
button: collectibleCopy;
}
+
+moderateBoxUserpic: UserpicButton(defaultUserpicButton) {
+ size: size(34px, 42px);
+ photoSize: 34px;
+ photoPosition: point(0px, 4px);
+}
+moderateBoxExpand: icon {{ "chat/reply_type_group", boxTextFg }};
+moderateBoxExpandHeight: 20px;
+moderateBoxExpandRight: 10px;
+moderateBoxExpandInnerSkip: 2px;
+moderateBoxExpandFont: font(11px);
+moderateBoxExpandToggleSize: 4px;
+moderateBoxExpandToggleFourStrokes: 3px;
+moderateBoxExpandIcon: icon{{ "info/edit/expand_arrow_small-flip_vertical", windowActiveTextFg }};
+moderateBoxExpandIconDown: icon{{ "info/edit/expand_arrow_small", windowActiveTextFg }};
+moderateBoxDividerLabel: FlatLabel(boxDividerLabel) {
+ palette: TextPalette(defaultTextPalette) {
+ selectLinkFg: windowActiveTextFg;
+ }
+}
diff --git a/Telegram/SourceFiles/boxes/create_poll_box.cpp b/Telegram/SourceFiles/boxes/create_poll_box.cpp
index 373899be4..1d02b5e52 100644
--- a/Telegram/SourceFiles/boxes/create_poll_box.cpp
+++ b/Telegram/SourceFiles/boxes/create_poll_box.cpp
@@ -7,33 +7,41 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/create_poll_box.h"
-#include "lang/lang_keys.h"
-#include "data/data_poll.h"
-#include "ui/toast/toast.h"
-#include "ui/wrap/vertical_layout.h"
-#include "ui/wrap/slide_wrap.h"
-#include "ui/wrap/fade_wrap.h"
-#include "ui/widgets/fields/input_field.h"
-#include "ui/widgets/shadow.h"
-#include "ui/widgets/labels.h"
-#include "ui/widgets/buttons.h"
-#include "ui/widgets/checkbox.h"
-#include "ui/text/text_utilities.h"
-#include "ui/vertical_list.h"
-#include "main/main_session.h"
-#include "core/application.h"
-#include "core/core_settings.h"
+#include "base/call_delayed.h"
+#include "base/event_filter.h"
+#include "base/random.h"
+#include "base/unique_qptr.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/message_field.h"
-#include "menu/menu_send.h"
+#include "chat_helpers/tabbed_panel.h"
+#include "chat_helpers/tabbed_selector.h"
+#include "core/application.h"
+#include "core/core_settings.h"
+#include "data/data_poll.h"
+#include "data/data_user.h"
+#include "data/stickers/data_custom_emoji.h"
#include "history/view/history_view_schedule_box.h"
-#include "base/unique_qptr.h"
-#include "base/event_filter.h"
-#include "base/call_delayed.h"
-#include "base/random.h"
+#include "lang/lang_keys.h"
+#include "main/main_session.h"
+#include "menu/menu_send.h"
+#include "ui/controls/emoji_button.h"
+#include "ui/rect.h"
+#include "ui/text/text_utilities.h"
+#include "ui/toast/toast.h"
+#include "ui/vertical_list.h"
+#include "ui/widgets/buttons.h"
+#include "ui/widgets/checkbox.h"
+#include "ui/widgets/fields/input_field.h"
+#include "ui/widgets/labels.h"
+#include "ui/widgets/shadow.h"
+#include "ui/wrap/fade_wrap.h"
+#include "ui/wrap/slide_wrap.h"
+#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
-#include "styles/style_layers.h"
#include "styles/style_boxes.h"
+#include "styles/style_chat_helpers.h" // defaultComposeFiles.
+#include "styles/style_layers.h"
+#include "styles/style_settings.h"
namespace {
@@ -46,12 +54,107 @@ constexpr auto kSolutionLimit = 200;
constexpr auto kWarnSolutionLimit = 60;
constexpr auto kErrorLimit = 99;
+[[nodiscard]] not_null AddEmojiToggleToField(
+ not_null field,
+ not_null box,
+ not_null controller,
+ not_null emojiPanel,
+ QPoint shift) {
+ const auto emojiToggle = Ui::CreateChild(
+ field->parentWidget(),
+ st::defaultComposeFiles.emoji);
+ const auto fade = Ui::CreateChild(
+ emojiToggle,
+ emojiToggle,
+ 0.5);
+ {
+ const auto fadeTarget = Ui::CreateChild(emojiToggle);
+ fadeTarget->resize(emojiToggle->size());
+ fadeTarget->paintRequest(
+ ) | rpl::start_with_next([=](const QRect &rect) {
+ auto p = QPainter(fadeTarget);
+ if (fade->animating()) {
+ p.fillRect(fadeTarget->rect(), st::boxBg);
+ }
+ fade->paint(p);
+ }, fadeTarget->lifetime());
+ rpl::single(false) | rpl::then(
+ field->focusedChanges()
+ ) | rpl::start_with_next([=](bool shown) {
+ if (shown) {
+ fade->fadeIn(st::universalDuration);
+ } else {
+ fade->fadeOut(st::universalDuration);
+ }
+ }, emojiToggle->lifetime());
+ fade->fadeOut(1);
+ fade->finish();
+ }
+
+
+ const auto outer = box->getDelegate()->outerContainer();
+ const auto allow = [](not_null) { return true; };
+ InitMessageFieldHandlers(
+ controller,
+ field,
+ Window::GifPauseReason::Layer,
+ allow);
+ Ui::Emoji::SuggestionsController::Init(
+ outer,
+ field,
+ &controller->session(),
+ Ui::Emoji::SuggestionsController::Options{
+ .suggestCustomEmoji = true,
+ .allowCustomWithoutPremium = allow,
+ });
+ const auto updateEmojiPanelGeometry = [=] {
+ const auto parent = emojiPanel->parentWidget();
+ const auto global = emojiToggle->mapToGlobal({ 0, 0 });
+ const auto local = parent->mapFromGlobal(global);
+ const auto right = local.x() + emojiToggle->width() * 3;
+ const auto isDropDown = local.y() < parent->height() / 2;
+ emojiPanel->setDropDown(isDropDown);
+ if (isDropDown) {
+ emojiPanel->moveTopRight(
+ local.y() + emojiToggle->height(),
+ right);
+ } else {
+ emojiPanel->moveBottomRight(local.y(), right);
+ }
+ };
+ rpl::combine(
+ box->sizeValue(),
+ field->geometryValue()
+ ) | rpl::start_with_next([=](QSize outer, QRect inner) {
+ emojiToggle->moveToLeft(
+ rect::right(inner) + shift.x(),
+ inner.y() + shift.y());
+ emojiToggle->update();
+ }, emojiToggle->lifetime());
+
+ emojiToggle->installEventFilter(emojiPanel);
+ emojiToggle->addClickHandler([=] {
+ updateEmojiPanelGeometry();
+ emojiPanel->toggleAnimated();
+ });
+ const auto filterCallback = [=](not_null event) {
+ if (event->type() == QEvent::Enter) {
+ updateEmojiPanelGeometry();
+ }
+ return base::EventFilterResult::Continue;
+ };
+ base::install_event_filter(emojiToggle, filterCallback);
+
+ return emojiToggle;
+}
+
class Options {
public:
Options(
- not_null outer,
+ not_null box,
not_null container,
- not_null session,
+ not_null controller,
+ ChatHelpers::TabbedPanel *emojiPanel,
bool chooseCorrectEnabled);
[[nodiscard]] bool hasOptions() const;
@@ -140,9 +243,10 @@ private:
[[nodiscard]] auto createChooseCorrectGroup()
-> std::shared_ptr;
- not_null _outer;
+ not_null _box;
not_null _container;
- const not_null _session;
+ const not_null _controller;
+ ChatHelpers::TabbedPanel * const _emojiPanel;
std::shared_ptr _chooseCorrectGroup;
int _position = 0;
std::vector> _list;
@@ -154,6 +258,7 @@ private:
rpl::event_stream> _scrollToWidget;
rpl::event_stream<> _backspaceInFront;
rpl::event_stream<> _tabbed;
+ rpl::lifetime _emojiPanelLifetime;
};
@@ -193,8 +298,9 @@ not_null CreateWarningLabel(
if (value >= 0) {
result->setText(QString::number(value));
} else {
+ constexpr auto kMinus = QChar(0x2212);
result->setMarkedText(Ui::Text::Colorized(
- QString::number(value)));
+ kMinus + QString::number(std::abs(value))));
}
result->setVisible(shown);
}));
@@ -223,7 +329,9 @@ Options::Option::Option(
, _field(
Ui::CreateChild(
_content.get(),
- st::createPollOptionField,
+ session->user()->isPremium()
+ ? st::createPollOptionFieldPremium
+ : st::createPollOptionField,
Ui::InputField::Mode::NoNewlines,
tr::lng_polls_create_option_add())) {
InitField(outer, _field, session);
@@ -299,7 +407,7 @@ void Options::Option::createRemove() {
const auto remove = Ui::CreateChild(
field.get(),
st::createPollOptionRemove);
- remove->hide(anim::type::instant);
+ remove->show(anim::type::instant);
const auto toggle = lifetime.make_state>(false);
_removeAlways = lifetime.make_state>(false);
@@ -309,6 +417,7 @@ void Options::Option::createRemove() {
// Don't capture 'this'! Because Option is a value type.
*toggle = !field->getLastText().isEmpty();
}, field->lifetime());
+#if 0
rpl::combine(
toggle->value(),
_removeAlways->value(),
@@ -316,6 +425,7 @@ void Options::Option::createRemove() {
) | rpl::start_with_next([=](bool shown) {
remove->toggle(shown, anim::type::normal);
}, remove->lifetime());
+#endif
field->widthValue(
) | rpl::start_with_next([=](int width) {
@@ -456,10 +566,16 @@ void Options::Option::removePlaceholder() const {
PollAnswer Options::Option::toPollAnswer(int index) const {
Expects(index >= 0 && index < kMaxOptionsCount);
+ const auto text = field()->getTextWithTags();
+
auto result = PollAnswer{
- field()->getLastText().trimmed(),
- QByteArray(1, ('0' + index))
+ TextWithEntities{
+ .text = text.text,
+ .entities = TextUtilities::ConvertTextTagsToEntities(text.tags),
+ },
+ QByteArray(1, ('0' + index)),
};
+ TextUtilities::Trim(result.text);
result.correct = _correct ? _correct->entity()->Checkbox::checked() : false;
return result;
}
@@ -469,13 +585,15 @@ rpl::producer Options::Option::removeClicks() const {
}
Options::Options(
- not_null outer,
+ not_null box,
not_null container,
- not_null session,
+ not_null controller,
+ ChatHelpers::TabbedPanel *emojiPanel,
bool chooseCorrectEnabled)
-: _outer(outer)
+: _box(box)
, _container(container)
-, _session(session)
+, _controller(controller)
+, _emojiPanel(emojiPanel)
, _chooseCorrectGroup(chooseCorrectEnabled
? createChooseCorrectGroup()
: nullptr)
@@ -645,12 +763,40 @@ void Options::addEmptyOption() {
(*(_list.end() - 2))->toggleRemoveAlways(true);
}
_list.push_back(std::make_unique