Merge tag 'v4.12.2' into dev
# Conflicts: # .github/workflows/win.yml # Telegram/Resources/winrc/Telegram.rc # Telegram/Resources/winrc/Updater.rc # Telegram/SourceFiles/core/version.h # Telegram/SourceFiles/settings/settings_advanced.cpp # Telegram/SourceFiles/settings/settings_main.cpp # Telegram/lib_ui # snap/snapcraft.yaml
4
.github/workflows/mac_packaged.yml
vendored
|
@ -40,7 +40,7 @@ jobs:
|
|||
|
||||
macos:
|
||||
name: MacOS
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-13
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
|
@ -67,6 +67,8 @@ jobs:
|
|||
|
||||
- name: First set up.
|
||||
run: |
|
||||
brew update
|
||||
brew upgrade || true
|
||||
brew install autoconf automake boost cmake ffmpeg openal-soft openssl opus ninja pkg-config python qt yasm xz
|
||||
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
|
||||
|
||||
|
|
78
.github/workflows/win.yml
vendored
|
@ -1,7 +1,6 @@
|
|||
name: Windows.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
|
@ -47,10 +46,11 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [Win32]
|
||||
arch: [Win32, x64]
|
||||
generator: ["", "Ninja Multi-Config"]
|
||||
|
||||
env:
|
||||
UPLOAD_ARTIFACT: "true"
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
ONLY_CACHE: "false"
|
||||
PREPARE_PATH: "Telegram/build/prepare/prepare.py"
|
||||
|
||||
|
@ -110,19 +110,42 @@ jobs:
|
|||
cd %TBUILD%
|
||||
%REPO_NAME%\Telegram\build\prepare\win.bat skip-release silent
|
||||
|
||||
- name: Read defines.
|
||||
- name: Read configuration matrix.
|
||||
shell: bash
|
||||
run: |
|
||||
ARTIFACT_NAME="Telegram"
|
||||
|
||||
ARCH=""
|
||||
if [ -n "${{ matrix.arch }}" ]; then
|
||||
case "${{ matrix.arch }}" in
|
||||
Win32) ARCH="x86";;
|
||||
*) ARCH="${{ matrix.arch }}";;
|
||||
esac
|
||||
echo "Architecture from matrix: $ARCH"
|
||||
ARTIFACT_NAME="${ARTIFACT_NAME}_${{ matrix.arch }}"
|
||||
fi
|
||||
|
||||
GENERATOR=""
|
||||
if [ -n "${{ matrix.generator }}" ]; then
|
||||
GENERATOR="-G \"${{ matrix.generator }}\""
|
||||
echo "Generator from matrix: $GENERATOR"
|
||||
ARTIFACT_NAME="${ARTIFACT_NAME}_${{ matrix.generator }}"
|
||||
fi
|
||||
echo "TDESKTOP_BUILD_GENERATOR=$GENERATOR" >> $GITHUB_ENV
|
||||
|
||||
[ -n "$GENERATOR" ] && ARCH=""
|
||||
echo "TDESKTOP_BUILD_ARCH=$ARCH" >> $GITHUB_ENV
|
||||
|
||||
DEFINE=""
|
||||
if [ -n "${{ matrix.defines }}" ]; then
|
||||
DEFINE="-D ${{ matrix.defines }}=ON"
|
||||
echo "Define from matrix: $DEFINE"
|
||||
echo "ARTIFACT_NAME=Telegram_${{ matrix.arch }}_${{ matrix.defines }}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "ARTIFACT_NAME=Telegram_${{ matrix.arch }}" >> $GITHUB_ENV
|
||||
ARTIFACT_NAME="${ARTIFACT_NAME}_${{ matrix.defines }}"
|
||||
fi
|
||||
echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV
|
||||
|
||||
echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV
|
||||
|
||||
API="-D TDESKTOP_API_TEST=ON"
|
||||
if [ $GITHUB_REF == 'refs/heads/nightly' ]; then
|
||||
echo "Use the open credentials."
|
||||
|
@ -143,50 +166,23 @@ jobs:
|
|||
cd %TBUILD%\%REPO_NAME%\Telegram
|
||||
|
||||
call configure.bat ^
|
||||
${{ matrix.arch }} ^
|
||||
%TDESKTOP_BUILD_GENERATOR% ^
|
||||
%TDESKTOP_BUILD_ARCH% ^
|
||||
%TDESKTOP_BUILD_API% ^
|
||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF ^
|
||||
-D DESKTOP_APP_NO_PDB=ON ^
|
||||
%TDESKTOP_BUILD_DEFINE% ^
|
||||
-DCMAKE_SYSTEM_VERSION=%SDK%
|
||||
%TDESKTOP_BUILD_DEFINE%
|
||||
|
||||
cd ..\out
|
||||
msbuild -m Telegram.sln /p:Configuration=Debug,Platform=${{ matrix.arch }},DebugSymbols=false,DebugType=none
|
||||
cmake --build ..\out --config Debug --parallel
|
||||
|
||||
- name: Move artifact.
|
||||
if: (env.UPLOAD_ARTIFACT == 'true') || ${{ github.ref == 'refs/heads/nightly' }}
|
||||
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
|
||||
run: |
|
||||
mkdir artifact
|
||||
move %TBUILD%\%REPO_NAME%\out\Debug\AyuGram.exe artifact/
|
||||
move %TBUILD%\%REPO_NAME%\out\Debug\Telegram.exe artifact/
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload artifact.
|
||||
if: (env.UPLOAD_ARTIFACT == 'true') || ${{ github.ref == 'refs/heads/nightly' }}
|
||||
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_NAME }}
|
||||
path: artifact\
|
||||
|
||||
release:
|
||||
name: Release
|
||||
needs: [windows]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Merge Releases
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: Telegram_Win32
|
||||
path: artifact
|
||||
|
||||
- name: Upload release
|
||||
uses: Hs1r1us/Release-AIO@v1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
# The name of the tag
|
||||
tag_name: prelease-${{ github.run_number }}
|
||||
prerelease: true
|
||||
release_name: Ayugram CI
|
||||
asset_files: './artifact'
|
||||
|
|
3
.gitmodules
vendored
|
@ -76,9 +76,6 @@
|
|||
[submodule "Telegram/lib_webview"]
|
||||
path = Telegram/lib_webview
|
||||
url = https://github.com/desktop-app/lib_webview.git
|
||||
[submodule "Telegram/ThirdParty/jemalloc"]
|
||||
path = Telegram/ThirdParty/jemalloc
|
||||
url = https://github.com/jemalloc/jemalloc
|
||||
[submodule "Telegram/ThirdParty/dispatch"]
|
||||
path = Telegram/ThirdParty/dispatch
|
||||
url = https://github.com/apple/swift-corelibs-libdispatch
|
||||
|
|
|
@ -10,8 +10,9 @@ if (APPLE)
|
|||
else()
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
endif()
|
||||
cmake_policy(SET CMP0076 NEW)
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
if (POLICY CMP0149)
|
||||
cmake_policy(SET CMP0149 NEW)
|
||||
endif()
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
|
|
|
@ -197,6 +197,8 @@ PRIVATE
|
|||
api/api_messages_search.h
|
||||
api/api_messages_search_merged.cpp
|
||||
api/api_messages_search_merged.h
|
||||
api/api_peer_colors.cpp
|
||||
api/api_peer_colors.h
|
||||
api/api_peer_photo.cpp
|
||||
api/api_peer_photo.h
|
||||
api/api_polls.cpp
|
||||
|
@ -447,16 +449,18 @@ PRIVATE
|
|||
chat_helpers/gifs_list_widget.h
|
||||
chat_helpers/message_field.cpp
|
||||
chat_helpers/message_field.h
|
||||
chat_helpers/share_message_phrase_factory.cpp
|
||||
chat_helpers/share_message_phrase_factory.h
|
||||
chat_helpers/spellchecker_common.cpp
|
||||
chat_helpers/spellchecker_common.h
|
||||
chat_helpers/stickers_dice_pack.cpp
|
||||
chat_helpers/stickers_dice_pack.h
|
||||
chat_helpers/stickers_emoji_image_loader.cpp
|
||||
chat_helpers/stickers_emoji_image_loader.h
|
||||
chat_helpers/stickers_emoji_pack.cpp
|
||||
chat_helpers/stickers_emoji_pack.h
|
||||
chat_helpers/stickers_gift_box_pack.cpp
|
||||
chat_helpers/stickers_gift_box_pack.h
|
||||
chat_helpers/stickers_dice_pack.cpp
|
||||
chat_helpers/stickers_dice_pack.h
|
||||
chat_helpers/stickers_list_footer.cpp
|
||||
chat_helpers/stickers_list_footer.h
|
||||
chat_helpers/stickers_list_widget.cpp
|
||||
|
@ -778,6 +782,8 @@ PRIVATE
|
|||
history/view/media/history_view_premium_gift.h
|
||||
history/view/media/history_view_service_box.cpp
|
||||
history/view/media/history_view_service_box.h
|
||||
history/view/media/history_view_similar_channels.cpp
|
||||
history/view/media/history_view_similar_channels.h
|
||||
history/view/media/history_view_slot_machine.cpp
|
||||
history/view/media/history_view_slot_machine.h
|
||||
history/view/media/history_view_sticker.cpp
|
||||
|
@ -853,6 +859,8 @@ PRIVATE
|
|||
history/view/history_view_service_message.h
|
||||
history/view/history_view_spoiler_click_handler.cpp
|
||||
history/view/history_view_spoiler_click_handler.h
|
||||
history/view/history_view_sponsored_click_handler.cpp
|
||||
history/view/history_view_sponsored_click_handler.h
|
||||
history/view/history_view_sticker_toast.cpp
|
||||
history/view/history_view_sticker_toast.h
|
||||
history/view/history_view_transcribe_button.cpp
|
||||
|
@ -958,6 +966,8 @@ PRIVATE
|
|||
info/profile/info_profile_widget.h
|
||||
info/settings/info_settings_widget.cpp
|
||||
info/settings/info_settings_widget.h
|
||||
info/similar_channels/info_similar_channels_widget.cpp
|
||||
info/similar_channels/info_similar_channels_widget.h
|
||||
info/statistics/info_statistics_common.h
|
||||
info/statistics/info_statistics_inner_widget.cpp
|
||||
info/statistics/info_statistics_inner_widget.h
|
||||
|
@ -1095,6 +1105,8 @@ PRIVATE
|
|||
media/stories/media_stories_recent_views.h
|
||||
media/stories/media_stories_reply.cpp
|
||||
media/stories/media_stories_reply.h
|
||||
media/stories/media_stories_repost_view.cpp
|
||||
media/stories/media_stories_repost_view.h
|
||||
media/stories/media_stories_share.cpp
|
||||
media/stories/media_stories_share.h
|
||||
media/stories/media_stories_sibling.cpp
|
||||
|
@ -1345,8 +1357,8 @@ PRIVATE
|
|||
settings/settings_calls.h
|
||||
settings/settings_codes.cpp
|
||||
settings/settings_codes.h
|
||||
settings/settings_common.cpp
|
||||
settings/settings_common.h
|
||||
settings/settings_common_session.cpp
|
||||
settings/settings_common_session.h
|
||||
settings/settings_experimental.cpp
|
||||
settings/settings_experimental.h
|
||||
settings/settings_folders.cpp
|
||||
|
@ -1506,6 +1518,7 @@ PRIVATE
|
|||
window/window_section_common.h
|
||||
window/window_session_controller.cpp
|
||||
window/window_session_controller.h
|
||||
window/window_session_controller_link_info.h
|
||||
window/window_slide_animation.cpp
|
||||
window/window_slide_animation.h
|
||||
window/window_top_bar_wrap.h
|
||||
|
@ -1798,6 +1811,10 @@ endif()
|
|||
set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
delayimp
|
||||
)
|
||||
target_link_options(Telegram
|
||||
PRIVATE
|
||||
/DELAYLOAD:secur32.dll
|
||||
|
@ -1854,6 +1871,10 @@ if (NOT DESKTOP_APP_DISABLE_AUTOUPDATE AND NOT build_macstore AND NOT build_wins
|
|||
)
|
||||
target_include_directories(Updater PRIVATE ${lib_base_loc})
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
target_link_libraries(Updater
|
||||
PRIVATE
|
||||
delayimp
|
||||
)
|
||||
target_link_options(Updater
|
||||
PRIVATE
|
||||
/DELAYLOAD:user32.dll
|
||||
|
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 785 B After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/chat/mini_lock.png
Normal file
After Width: | Height: | Size: 266 B |
BIN
Telegram/Resources/icons/chat/mini_lock@2x.png
Normal file
After Width: | Height: | Size: 358 B |
BIN
Telegram/Resources/icons/chat/mini_lock@3x.png
Normal file
After Width: | Height: | Size: 489 B |
BIN
Telegram/Resources/icons/chat/mini_subscribers.png
Normal file
After Width: | Height: | Size: 261 B |
BIN
Telegram/Resources/icons/chat/mini_subscribers@2x.png
Normal file
After Width: | Height: | Size: 399 B |
BIN
Telegram/Resources/icons/chat/mini_subscribers@3x.png
Normal file
After Width: | Height: | Size: 557 B |
BIN
Telegram/Resources/icons/info/edit/stickers_add.png
Normal file
After Width: | Height: | Size: 470 B |
BIN
Telegram/Resources/icons/info/edit/stickers_add@2x.png
Normal file
After Width: | Height: | Size: 899 B |
BIN
Telegram/Resources/icons/info/edit/stickers_add@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/mediaview/mini_repost.png
Normal file
After Width: | Height: | Size: 481 B |
BIN
Telegram/Resources/icons/mediaview/mini_repost@2x.png
Normal file
After Width: | Height: | Size: 780 B |
BIN
Telegram/Resources/icons/mediaview/mini_repost@3x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/menu/mode_messages.png
Normal file
After Width: | Height: | Size: 745 B |
BIN
Telegram/Resources/icons/menu/mode_messages@2x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/menu/mode_messages@3x.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
Telegram/Resources/icons/menu/mode_topics.png
Normal file
After Width: | Height: | Size: 913 B |
BIN
Telegram/Resources/icons/menu/mode_topics@2x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
Telegram/Resources/icons/menu/mode_topics@3x.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
Telegram/Resources/icons/statistics/mini_stats_like.png
Normal file
After Width: | Height: | Size: 497 B |
BIN
Telegram/Resources/icons/statistics/mini_stats_like@2x.png
Normal file
After Width: | Height: | Size: 976 B |
BIN
Telegram/Resources/icons/statistics/mini_stats_like@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/statistics/mini_stats_share.png
Normal file
After Width: | Height: | Size: 465 B |
BIN
Telegram/Resources/icons/statistics/mini_stats_share@2x.png
Normal file
After Width: | Height: | Size: 855 B |
BIN
Telegram/Resources/icons/statistics/mini_stats_share@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
|
@ -839,6 +839,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"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_background_apply_me" = "Apply for me";
|
||||
"lng_background_apply_both" = "Apply for me and {user}";
|
||||
|
||||
"lng_download_path_ask" = "Ask download path for each file";
|
||||
"lng_download_path" = "Download path";
|
||||
|
@ -1175,6 +1177,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_profile_bot_privacy" = "Bot Privacy Policy";
|
||||
"lng_profile_common_groups#one" = "{count} group in common";
|
||||
"lng_profile_common_groups#other" = "{count} groups in common";
|
||||
"lng_profile_similar_channels#one" = "{count} similar channel";
|
||||
"lng_profile_similar_channels#other" = "{count} similar channels";
|
||||
"lng_profile_participants_section" = "Members";
|
||||
"lng_profile_subscribers_section" = "Subscribers";
|
||||
"lng_profile_add_contact" = "Add Contact";
|
||||
|
@ -1347,6 +1351,13 @@ 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_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.";
|
||||
"lng_manage_peer_reactions_level#other" = "Your channel needs to reach level **{count}** to use **{same_count}** custom reactions.";
|
||||
"lng_manage_peer_reactions_boost" = "Boost your channel {link}.";
|
||||
"lng_manage_peer_reactions_boost_link" = "here";
|
||||
"lng_manage_peer_reactions_limit" = "Channels can't have more custom reactions.";
|
||||
|
||||
"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.";
|
||||
|
@ -1641,11 +1652,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_action_suggested_video_button" = "View Video";
|
||||
"lng_action_attach_menu_bot_allowed" = "You allowed this bot to message you when you added it in the attachment menu.";
|
||||
"lng_action_webapp_bot_allowed" = "You allowed this bot to message you in his web-app.";
|
||||
"lng_action_set_wallpaper_me" = "You set a new wallpaper for this chat";
|
||||
"lng_action_set_wallpaper" = "{user} set a new wallpaper for this chat";
|
||||
"lng_action_set_wallpaper_me" = "You set a new wallpaper for this chat.";
|
||||
"lng_action_set_wallpaper" = "{user} set a new wallpaper for this chat.";
|
||||
"lng_action_set_wallpaper_both_me" = "You set a new wallpaper for {user} and you.";
|
||||
"lng_action_set_wallpaper_button" = "View Wallpaper";
|
||||
"lng_action_set_same_wallpaper_me" = "You set the same wallpaper for this chat";
|
||||
"lng_action_set_same_wallpaper" = "{user} set the same wallpaper for this chat";
|
||||
"lng_action_set_wallpaper_remove" = "Remove";
|
||||
"lng_action_set_same_wallpaper_me" = "You set the same wallpaper for this chat.";
|
||||
"lng_action_set_same_wallpaper" = "{user} set the same wallpaper for this chat.";
|
||||
"lng_action_topic_created_inside" = "Topic created";
|
||||
"lng_action_topic_closed_inside" = "Topic closed";
|
||||
"lng_action_topic_reopened_inside" = "Topic reopened";
|
||||
|
@ -1667,6 +1680,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"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_action_giveaway_started" = "{from} just started a giveaway of Telegram Premium subscriptions to its followers.";
|
||||
"lng_action_giveaway_results#one" = "{count} winner of the giveaway was randomly selected by Telegram and received private messages with giftcodes.";
|
||||
"lng_action_giveaway_results#other" = "{count} winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes.";
|
||||
"lng_action_giveaway_results_some" = "Some winners of the giveaway was randomly selected by Telegram and received private messages with giftcodes.";
|
||||
"lng_action_giveaway_results_none" = "No winners of the giveaway could be selected.";
|
||||
|
||||
"lng_similar_channels_title" = "Similar channels";
|
||||
"lng_similar_channels_view_all" = "View all";
|
||||
"lng_similar_channels_more" = "More Channels";
|
||||
"lng_similar_channels_premium_all#one" = "Subscribe to {link} to unlock up to **{count}** similar channel.";
|
||||
"lng_similar_channels_premium_all#other" = "Subscribe to {link} to unlock up to **{count}** similar channels.";
|
||||
"lng_similar_channels_premium_all_link" = "Telegram Premium";
|
||||
"lng_similar_channels_show_more" = "Show more channels";
|
||||
|
||||
"lng_premium_gift_duration_months#one" = "for {count} month";
|
||||
"lng_premium_gift_duration_months#other" = "for {count} months";
|
||||
|
@ -1808,8 +1833,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_forwarded_hidden" = "The account was hidden by the user.";
|
||||
"lng_forwarded_imported" = "This message was imported from another app. It may not be real.";
|
||||
"lng_signed_author" = "Author: {user}";
|
||||
"lng_sponsored" = "sponsored";
|
||||
"lng_recommended" = "recommended";
|
||||
"lng_sponsored_message_title" = "Sponsored";
|
||||
"lng_recommended_message_title" = "Recommended";
|
||||
"lng_edited" = "edited";
|
||||
"lng_edited_date" = "Edited: {date}";
|
||||
"lng_sent_date" = "Sent: {date}";
|
||||
|
@ -1921,6 +1946,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_premium_summary_subtitle_gift#other" = "{user} has gifted you a {count}-months subscription for Telegram Premium.";
|
||||
"lng_premium_summary_subtitle_gift_me#one" = "You gifted {user} a {count}-month subscription for Telegram Premium.";
|
||||
"lng_premium_summary_subtitle_gift_me#other" = "You gifted {user} a {count}-months subscription for Telegram Premium.";
|
||||
"lng_premium_summary_subtitle_wallpapers" = "Wallpapers for Both Sides";
|
||||
"lng_premium_summary_about_wallpapers" = "Set custom wallpapers for you and your chat partner.";
|
||||
"lng_premium_summary_subtitle_stories" = "Upgraded Stories";
|
||||
"lng_premium_summary_about_stories" = "Priority order, stealth mode, permanent views history and more.";
|
||||
"lng_premium_summary_subtitle_double_limits" = "Doubled Limits";
|
||||
|
@ -2083,6 +2110,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_boost_channel_title_color" = "Enable colors";
|
||||
"lng_boost_channel_needs_level_color#one" = "Your channel needs to reach **Level {count}** to change channel color.";
|
||||
"lng_boost_channel_needs_level_color#other" = "Your channel needs to reach **Level {count}** to change channel color.";
|
||||
|
||||
"lng_boost_channel_title_reactions" = "Custom reactions";
|
||||
"lng_boost_channel_needs_level_reactions#one" = "Your channel needs to reach **Level {count}** to add **{same_count}** custom emoji as a reaction.";
|
||||
"lng_boost_channel_needs_level_reactions#other" = "Your channel needs to reach **Level {count}** to add **{same_count}** custom emoji as reactions.";
|
||||
|
||||
"lng_boost_channel_ask" = "Ask your **Premium** subscribers to boost your channel with this link:";
|
||||
"lng_boost_channel_ask_button" = "Copy Link";
|
||||
"lng_boost_channel_or" = "or";
|
||||
|
@ -2746,6 +2778,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_share_wrong_user" = "This game was opened from a different user.";
|
||||
"lng_share_game_link_copied" = "Game link copied to clipboard.";
|
||||
"lng_share_done" = "Done!";
|
||||
"lng_share_message_to_saved_messages" = "Message forwarded to **Saved Messages**.";
|
||||
"lng_share_messages_to_saved_messages" = "Messages forwarded to **Saved Messages**.";
|
||||
"lng_share_message_to_chat" = "Message forwarded to **{chat}**.";
|
||||
"lng_share_messages_to_chat" = "Messages forwarded to **{chat}**.";
|
||||
"lng_share_message_to_two_chats" = "Message forwarded to **{user}** and **{chat}**.";
|
||||
"lng_share_messages_to_two_chats" = "Messages forwarded to **{user}** and **{chat}**.";
|
||||
"lng_share_message_to_many_chats#one" = "Message forwarded to **{count} chat**.";
|
||||
"lng_share_message_to_many_chats#other" = "Message forwarded to **{count} chats**.";
|
||||
"lng_share_messages_to_many_chats#one" = "Messages forwarded to **{count} chat**.";
|
||||
"lng_share_messages_to_many_chats#other" = "Messages forwarded to **{count} chats**.";
|
||||
|
||||
"lng_contact_phone" = "Phone Number";
|
||||
"lng_enter_contact_data" = "New Contact";
|
||||
|
@ -3294,6 +3336,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_audio_player_reverse" = "Reverse order";
|
||||
"lng_audio_player_shuffle" = "Shuffle";
|
||||
"lng_audio_transcribe_long" = "This voice message is too long.";
|
||||
"lng_audio_transcribe_trials_left#one" = "You have {count} free transcription left until {date}.";
|
||||
"lng_audio_transcribe_trials_left#other" = "You have {count} free transcriptions left until {date}.";
|
||||
"lng_audio_transcribe_trials_over" = "You have used all your free transcriptions this week. Wait until {date} to use it again or subscribe to {link} now.";
|
||||
|
||||
"lng_rights_edit_admin" = "Manage permissions";
|
||||
"lng_rights_edit_admin_header" = "What can this admin do?";
|
||||
|
@ -4096,6 +4141,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_view_button_request_join" = "Request to Join";
|
||||
"lng_view_button_external_link" = "Open link";
|
||||
"lng_view_button_boost" = "Boost";
|
||||
"lng_view_button_giftcode" = "Open";
|
||||
|
||||
"lng_sponsored_hide_ads" = "Hide";
|
||||
"lng_sponsored_title" = "What are sponsored messages?";
|
||||
|
@ -4141,10 +4187,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_forum_topics_no_discussion" = "Topics can't be enabled in discussion groups at the moment.";
|
||||
"lng_forum_choose_title_and_icon" = "Choose title and icon for your topic";
|
||||
"lng_forum_replies_only" = "You can reply to messages in topics.";
|
||||
"lng_forum_message_in" = "Message in {topic}";
|
||||
"lng_forum_reply_in" = "Reply in {topic}";
|
||||
"lng_forum_no_topics" = "No topics currently created in this forum.";
|
||||
"lng_forum_create_topic" = "Create topic";
|
||||
"lng_forum_discard_sure" = "Are you sure you want to discard this topic?";
|
||||
"lng_forum_view_as_messages" = "View as Messages";
|
||||
"lng_forum_view_as_topics" = "View as Topics";
|
||||
"lng_forum_no_messages" = "No messages";
|
||||
"lng_forum_messages#one" = "{count} message";
|
||||
"lng_forum_messages#other" = "{count} messages";
|
||||
|
@ -4286,12 +4335,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
"lng_stats_title" = "Statistics";
|
||||
"lng_stats_message_title" = "Message Statistic";
|
||||
"lng_stats_story_title" = "Story Statistic";
|
||||
"lng_stats_zoom_out" = "Zoom Out";
|
||||
|
||||
"lng_stats_day_month_year" = "{days_count} {month} {year}";
|
||||
"lng_stats_day_month" = "{days_count} {month}";
|
||||
"lng_stats_weekday_day_month_year" = "{day}, {days_count} {month} {year}";
|
||||
"lng_stats_weekday_day_month_time" = "{day}, {days_count} {month} {time}";
|
||||
|
||||
"lng_stats_overview_title" = "Overview";
|
||||
"lng_stats_overview_member_count" = "Followers";
|
||||
"lng_stats_overview_mean_view_count" = "Views Per Post";
|
||||
"lng_stats_overview_mean_share_count" = "Shared Per Post";
|
||||
"lng_stats_overview_mean_reactions_count" = "Reactions Per Post";
|
||||
"lng_stats_overview_mean_story_view_count" = "Views Per Story";
|
||||
"lng_stats_overview_mean_story_share_count" = "Shared Per Story";
|
||||
"lng_stats_overview_mean_story_reactions_count" = "Reactions Per Story";
|
||||
"lng_stats_overview_enabled_notifications" = "Enabled Notifications";
|
||||
"lng_stats_overview_messages" = "Messages";
|
||||
"lng_stats_overview_group_mean_view_count" = "Viewing Members";
|
||||
|
@ -4321,8 +4380,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_stats_recent_messages_title" = "Recent posts";
|
||||
"lng_stats_recent_messages_views#one" = "{count} view";
|
||||
"lng_stats_recent_messages_views#other" = "{count} views";
|
||||
"lng_stats_recent_messages_shares#one" = "{count} share";
|
||||
"lng_stats_recent_messages_shares#other" = "{count} shares";
|
||||
|
||||
"lng_stats_loading" = "Loading stats...";
|
||||
"lng_stats_loading_subtext" = "Please wait a few moments while we generate your stats.";
|
||||
|
@ -4336,6 +4393,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_chart_title_language" = "Languages";
|
||||
"lng_chart_title_message_interaction" = "Interactions";
|
||||
"lng_chart_title_instant_view_interaction" = "IV Interactions";
|
||||
"lng_chart_title_reactions_by_emotion" = "Reactions";
|
||||
"lng_chart_title_story_interactions" = "Story Interactions";
|
||||
"lng_chart_title_story_reactions_by_emotion" = "Story reactions";
|
||||
|
||||
"lng_chart_title_group_join" = "Group members";
|
||||
"lng_chart_title_group_join_by_source" = "New members by source";
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="4.11.7.0" />
|
||||
Version="4.12.2.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
|
|
@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,11,7,0
|
||||
PRODUCTVERSION 4,11,7,0
|
||||
FILEVERSION 4,12,2,0
|
||||
PRODUCTVERSION 4,12,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -62,10 +62,10 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "Radolyn Labs"
|
||||
VALUE "FileDescription", "AyuGram Desktop"
|
||||
VALUE "FileVersion", "4.11.7.0"
|
||||
VALUE "FileVersion", "4.12.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "4.11.7.0"
|
||||
VALUE "ProductVersion", "4.12.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,11,7,0
|
||||
PRODUCTVERSION 4,11,7,0
|
||||
FILEVERSION 4,12,2,0
|
||||
PRODUCTVERSION 4,12,2,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.11.7.0"
|
||||
VALUE "FileVersion", "4.12.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "4.11.7.0"
|
||||
VALUE "ProductVersion", "4.12.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
@ -20,12 +20,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/controls/filter_link_header.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_filter_icons.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
@ -341,7 +341,7 @@ void ToggleChatsController::setupAboveWidget() {
|
|||
_addedTopWidget = container->add(object_ptr<Ui::RpWidget>(container));
|
||||
const auto realAbove = container->add(
|
||||
object_ptr<Ui::VerticalLayout>(container));
|
||||
AddDivider(realAbove);
|
||||
Ui::AddDivider(realAbove);
|
||||
const auto totalCount = [&] {
|
||||
if (_chats.empty()) {
|
||||
return _additional.size();
|
||||
|
@ -422,7 +422,7 @@ void ToggleChatsController::setupBelowWidget() {
|
|||
auto widget = object_ptr<Ui::DividerLabel>(
|
||||
(QWidget*)nullptr,
|
||||
std::move(layout),
|
||||
st::settingsDividerLabelPadding);
|
||||
st::defaultBoxDividerLabelPadding);
|
||||
raw->add(object_ptr<Ui::FlatLabel>(
|
||||
raw,
|
||||
(_action == ToggleAction::Removing
|
||||
|
|
|
@ -211,6 +211,29 @@ void ApplyBotsList(
|
|||
Data::PeerUpdate::Flag::FullInfo);
|
||||
}
|
||||
|
||||
[[nodiscard]] ChatParticipants::Channels ParseSimilar(
|
||||
not_null<ChannelData*> channel,
|
||||
const MTPmessages_Chats &chats) {
|
||||
auto result = ChatParticipants::Channels();
|
||||
std::vector<not_null<ChannelData*>>();
|
||||
chats.match([&](const auto &data) {
|
||||
const auto &list = data.vchats().v;
|
||||
result.list.reserve(list.size());
|
||||
for (const auto &chat : list) {
|
||||
const auto peer = channel->owner().processChat(chat);
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
result.list.push_back(channel);
|
||||
}
|
||||
}
|
||||
if constexpr (MTPDmessages_chatsSlice::Is<decltype(data)>()) {
|
||||
if (channel->session().premiumPossible()) {
|
||||
result.more = data.vcount().v - data.vchats().v.size();
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ChatParticipant::ChatParticipant(
|
||||
|
@ -685,4 +708,50 @@ void ChatParticipants::unblock(
|
|||
_kickRequests.emplace(kick, requestId);
|
||||
}
|
||||
|
||||
void ChatParticipants::loadSimilarChannels(not_null<ChannelData*> channel) {
|
||||
if (!channel->isBroadcast()) {
|
||||
return;
|
||||
} else if (const auto i = _similar.find(channel); i != end(_similar)) {
|
||||
if (i->second.requestId
|
||||
|| !i->second.channels.more
|
||||
|| !channel->session().premium()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_similar[channel].requestId = _api.request(
|
||||
MTPchannels_GetChannelRecommendations(channel->inputChannel)
|
||||
).done([=](const MTPmessages_Chats &result) {
|
||||
auto &similar = _similar[channel];
|
||||
similar.requestId = 0;
|
||||
auto parsed = ParseSimilar(channel, result);
|
||||
if (similar.channels == parsed) {
|
||||
return;
|
||||
}
|
||||
similar.channels = std::move(parsed);
|
||||
if (const auto history = channel->owner().historyLoaded(channel)) {
|
||||
if (const auto item = history->joinedMessageInstance()) {
|
||||
history->owner().requestItemResize(item);
|
||||
}
|
||||
}
|
||||
_similarLoaded.fire_copy(channel);
|
||||
}).send();
|
||||
}
|
||||
|
||||
auto ChatParticipants::similar(not_null<ChannelData*> channel)
|
||||
-> const Channels & {
|
||||
const auto i = channel->isBroadcast()
|
||||
? _similar.find(channel)
|
||||
: end(_similar);
|
||||
if (i != end(_similar)) {
|
||||
return i->second.channels;
|
||||
}
|
||||
static const auto empty = Channels();
|
||||
return empty;
|
||||
}
|
||||
|
||||
auto ChatParticipants::similarLoaded() const
|
||||
-> rpl::producer<not_null<ChannelData*>> {
|
||||
return _similarLoaded.events();
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
|
|
@ -120,7 +120,26 @@ public:
|
|||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> participant);
|
||||
|
||||
void loadSimilarChannels(not_null<ChannelData*> channel);
|
||||
|
||||
struct Channels {
|
||||
std::vector<not_null<ChannelData*>> list;
|
||||
int more = 0;
|
||||
|
||||
friend inline bool operator==(
|
||||
const Channels &,
|
||||
const Channels &) = default;
|
||||
};
|
||||
[[nodiscard]] const Channels &similar(not_null<ChannelData*> channel);
|
||||
[[nodiscard]] auto similarLoaded() const
|
||||
-> rpl::producer<not_null<ChannelData*>>;
|
||||
|
||||
private:
|
||||
struct SimilarChannels {
|
||||
Channels channels;
|
||||
mtpRequestId requestId = 0;
|
||||
};
|
||||
|
||||
MTP::Sender _api;
|
||||
|
||||
using PeerRequests = base::flat_map<PeerData*, mtpRequestId>;
|
||||
|
@ -143,6 +162,9 @@ private:
|
|||
not_null<PeerData*>>;
|
||||
base::flat_map<KickRequest, mtpRequestId> _kickRequests;
|
||||
|
||||
base::flat_map<not_null<ChannelData*>, SimilarChannels> _similar;
|
||||
rpl::event_stream<not_null<ChannelData*>> _similarLoaded;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
|
|
126
Telegram/SourceFiles/api/api_peer_colors.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_peer_colors.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto kRequestEach = 3600 * crl::time(1000);
|
||||
|
||||
} // namespace
|
||||
|
||||
PeerColors::PeerColors(not_null<ApiWrap*> api)
|
||||
: _api(&api->instance())
|
||||
, _timer([=] { request(); }) {
|
||||
request();
|
||||
_timer.callEach(kRequestEach);
|
||||
}
|
||||
|
||||
PeerColors::~PeerColors() = default;
|
||||
|
||||
void PeerColors::request() {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
_requestId = _api.request(MTPhelp_GetPeerColors(
|
||||
MTP_int(_hash)
|
||||
)).done([=](const MTPhelp_PeerColors &result) {
|
||||
_requestId = 0;
|
||||
result.match([&](const MTPDhelp_peerColors &data) {
|
||||
_hash = data.vhash().v;
|
||||
apply(data);
|
||||
}, [](const MTPDhelp_peerColorsNotModified &) {
|
||||
});
|
||||
}).fail([=] {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
std::vector<uint8> PeerColors::suggested() const {
|
||||
return _suggested.current();
|
||||
}
|
||||
|
||||
rpl::producer<std::vector<uint8>> PeerColors::suggestedValue() const {
|
||||
return _suggested.value();
|
||||
}
|
||||
|
||||
auto PeerColors::indicesValue() const
|
||||
-> rpl::producer<Ui::ColorIndicesCompressed> {
|
||||
return rpl::single(_colorIndicesCurrent
|
||||
? *_colorIndicesCurrent
|
||||
: Ui::ColorIndicesCompressed()
|
||||
) | rpl::then(_colorIndicesChanged.events() | rpl::map([=] {
|
||||
return *_colorIndicesCurrent;
|
||||
}));
|
||||
}
|
||||
|
||||
void PeerColors::apply(const MTPDhelp_peerColors &data) {
|
||||
auto suggested = std::vector<uint8>();
|
||||
auto colors = std::make_shared<
|
||||
std::array<Ui::ColorIndexData, Ui::kColorIndexCount>>();
|
||||
|
||||
using ParsedColor = std::array<uint32, Ui::kColorPatternsCount>;
|
||||
const auto parseColors = [](const MTPhelp_PeerColorSet &set) {
|
||||
return set.match([&](const MTPDhelp_peerColorSet &data) {
|
||||
auto result = ParsedColor();
|
||||
const auto &list = data.vcolors().v;
|
||||
if (list.empty() || list.size() > Ui::kColorPatternsCount) {
|
||||
LOG(("API Error: Bad count for PeerColorSet.colors: %1"
|
||||
).arg(list.size()));
|
||||
return ParsedColor();
|
||||
}
|
||||
auto fill = result.data();
|
||||
for (const auto &color : list) {
|
||||
*fill++ = (uint32(1) << 24) | uint32(color.v);
|
||||
}
|
||||
return result;
|
||||
}, [](const MTPDhelp_peerColorProfileSet &) {
|
||||
LOG(("API Error: peerColorProfileSet in colors result!"));
|
||||
return ParsedColor();
|
||||
});
|
||||
};
|
||||
|
||||
const auto &list = data.vcolors().v;
|
||||
suggested.reserve(list.size());
|
||||
for (const auto &color : list) {
|
||||
const auto &data = color.data();
|
||||
const auto colorIndexBare = data.vcolor_id().v;
|
||||
if (colorIndexBare < 0 || colorIndexBare >= Ui::kColorIndexCount) {
|
||||
LOG(("API Error: Bad color index: %1").arg(colorIndexBare));
|
||||
continue;
|
||||
}
|
||||
const auto colorIndex = uint8(colorIndexBare);
|
||||
if (!data.is_hidden()) {
|
||||
suggested.push_back(colorIndex);
|
||||
}
|
||||
if (const auto light = data.vcolors()) {
|
||||
auto &fields = (*colors)[colorIndex];
|
||||
fields.light = parseColors(*light);
|
||||
if (const auto dark = data.vdark_colors()) {
|
||||
fields.dark = parseColors(*dark);
|
||||
} else {
|
||||
fields.dark = fields.light;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_colorIndicesCurrent) {
|
||||
_colorIndicesCurrent = std::make_unique<Ui::ColorIndicesCompressed>(
|
||||
Ui::ColorIndicesCompressed{ std::move(colors) });
|
||||
_colorIndicesChanged.fire({});
|
||||
} else if (*_colorIndicesCurrent->colors != *colors) {
|
||||
_colorIndicesCurrent->colors = std::move(colors);
|
||||
_colorIndicesChanged.fire({});
|
||||
}
|
||||
_suggested = std::move(suggested);
|
||||
}
|
||||
|
||||
} // namespace Api
|
46
Telegram/SourceFiles/api/api_peer_colors.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/timer.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class ApiWrap;
|
||||
|
||||
namespace Ui {
|
||||
struct ColorIndicesCompressed;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Api {
|
||||
|
||||
class PeerColors final {
|
||||
public:
|
||||
explicit PeerColors(not_null<ApiWrap*> api);
|
||||
~PeerColors();
|
||||
|
||||
[[nodiscard]] std::vector<uint8> suggested() const;
|
||||
[[nodiscard]] rpl::producer<std::vector<uint8>> suggestedValue() const;
|
||||
[[nodiscard]] auto indicesValue() const
|
||||
-> rpl::producer<Ui::ColorIndicesCompressed>;
|
||||
|
||||
private:
|
||||
void request();
|
||||
void apply(const MTPDhelp_peerColors &data);
|
||||
|
||||
MTP::Sender _api;
|
||||
int32 _hash = 0;
|
||||
|
||||
mtpRequestId _requestId = 0;
|
||||
base::Timer _timer;
|
||||
rpl::variable<std::vector<uint8>> _suggested;
|
||||
rpl::event_stream<> _colorIndicesChanged;
|
||||
std::unique_ptr<Ui::ColorIndicesCompressed> _colorIndicesCurrent;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
|
@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -62,15 +61,25 @@ constexpr auto kCheckRequestsTimer = 10 * crl::time(1000);
|
|||
tlUnmuted.vpart().v / tlUnmuted.vtotal().v * 100.,
|
||||
0.,
|
||||
100.);
|
||||
using Recent = MTPMessageInteractionCounters;
|
||||
using Recent = MTPPostInteractionCounters;
|
||||
auto recentMessages = ranges::views::all(
|
||||
data.vrecent_message_interactions().v
|
||||
data.vrecent_posts_interactions().v
|
||||
) | ranges::views::transform([&](const Recent &tl) {
|
||||
return Data::StatisticsMessageInteractionInfo{
|
||||
.messageId = tl.data().vmsg_id().v,
|
||||
.viewsCount = tl.data().vviews().v,
|
||||
.forwardsCount = tl.data().vforwards().v,
|
||||
};
|
||||
return tl.match([&](const MTPDpostInteractionCountersStory &data) {
|
||||
return Data::StatisticsMessageInteractionInfo{
|
||||
.storyId = data.vstory_id().v,
|
||||
.viewsCount = data.vviews().v,
|
||||
.forwardsCount = data.vforwards().v,
|
||||
.reactionsCount = data.vreactions().v,
|
||||
};
|
||||
}, [&](const MTPDpostInteractionCountersMessage &data) {
|
||||
return Data::StatisticsMessageInteractionInfo{
|
||||
.messageId = data.vmsg_id().v,
|
||||
.viewsCount = data.vviews().v,
|
||||
.forwardsCount = data.vforwards().v,
|
||||
.reactionsCount = data.vreactions().v,
|
||||
};
|
||||
});
|
||||
}) | ranges::to_vector;
|
||||
|
||||
return {
|
||||
|
@ -80,6 +89,15 @@ constexpr auto kCheckRequestsTimer = 10 * crl::time(1000);
|
|||
.memberCount = StatisticalValueFromTL(data.vfollowers()),
|
||||
.meanViewCount = StatisticalValueFromTL(data.vviews_per_post()),
|
||||
.meanShareCount = StatisticalValueFromTL(data.vshares_per_post()),
|
||||
.meanReactionCount = StatisticalValueFromTL(
|
||||
data.vreactions_per_post()),
|
||||
|
||||
.meanStoryViewCount = StatisticalValueFromTL(
|
||||
data.vviews_per_story()),
|
||||
.meanStoryShareCount = StatisticalValueFromTL(
|
||||
data.vshares_per_story()),
|
||||
.meanStoryReactionCount = StatisticalValueFromTL(
|
||||
data.vreactions_per_story()),
|
||||
|
||||
.enabledNotificationsPercentage = unmuted,
|
||||
|
||||
|
@ -110,6 +128,15 @@ constexpr auto kCheckRequestsTimer = 10 * crl::time(1000);
|
|||
.instantViewInteractionGraph = StatisticalGraphFromTL(
|
||||
data.viv_interactions_graph()),
|
||||
|
||||
.reactionsByEmotionGraph = StatisticalGraphFromTL(
|
||||
data.vreactions_by_emotion_graph()),
|
||||
|
||||
.storyInteractionsGraph = StatisticalGraphFromTL(
|
||||
data.vstory_interactions_graph()),
|
||||
|
||||
.storyReactionsByEmotionGraph = StatisticalGraphFromTL(
|
||||
data.vstory_reactions_by_emotion_graph()),
|
||||
|
||||
.recentMessageInteractions = std::move(recentMessages),
|
||||
};
|
||||
}
|
||||
|
@ -324,7 +351,7 @@ Data::SupergroupStatistics Statistics::supergroupStats() const {
|
|||
|
||||
PublicForwards::PublicForwards(
|
||||
not_null<ChannelData*> channel,
|
||||
FullMsgId fullId)
|
||||
Data::RecentPostId fullId)
|
||||
: StatisticsRequestSender(channel)
|
||||
, _fullId(fullId) {
|
||||
}
|
||||
|
@ -332,9 +359,20 @@ PublicForwards::PublicForwards(
|
|||
void PublicForwards::request(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done) {
|
||||
if (_requestId) {
|
||||
return;
|
||||
if (!_requestId) {
|
||||
if (_fullId.messageId) {
|
||||
requestMessage(token, std::move(done));
|
||||
} else if (_fullId.storyId) {
|
||||
requestStory(token, std::move(done));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PublicForwards::requestMessage(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done) {
|
||||
Expects(_fullId.messageId);
|
||||
|
||||
const auto offsetPeer = channel()->owner().peer(token.fullId.peer);
|
||||
const auto tlOffsetPeer = offsetPeer
|
||||
? offsetPeer->input
|
||||
|
@ -342,13 +380,13 @@ void PublicForwards::request(
|
|||
constexpr auto kLimit = tl::make_int(100);
|
||||
_requestId = makeRequest(MTPstats_GetMessagePublicForwards(
|
||||
channel()->inputChannel,
|
||||
MTP_int(_fullId.msg),
|
||||
MTP_int(_fullId.messageId.msg),
|
||||
MTP_int(token.rate),
|
||||
tlOffsetPeer,
|
||||
MTP_int(token.fullId.msg),
|
||||
kLimit
|
||||
)).done([=, channel = channel()](const MTPmessages_Messages &result) {
|
||||
using Messages = QVector<FullMsgId>;
|
||||
using Messages = QVector<Data::RecentPostId>;
|
||||
_requestId = 0;
|
||||
|
||||
auto nextToken = Data::PublicForwardsSlice::OffsetToken();
|
||||
|
@ -365,7 +403,7 @@ void PublicForwards::request(
|
|||
MessageFlags(),
|
||||
NewMessageType::Existing);
|
||||
nextToken.fullId = { peerId, msgId };
|
||||
result.push_back(nextToken.fullId);
|
||||
result.push_back({ .messageId = nextToken.fullId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -420,14 +458,90 @@ void PublicForwards::request(
|
|||
}).send();
|
||||
}
|
||||
|
||||
void PublicForwards::requestStory(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done) {
|
||||
Expects(_fullId.storyId);
|
||||
|
||||
constexpr auto kLimit = tl::make_int(100);
|
||||
_requestId = makeRequest(MTPstats_GetStoryPublicForwards(
|
||||
channel()->input,
|
||||
MTP_int(_fullId.storyId.story),
|
||||
MTP_string(token.storyOffset),
|
||||
kLimit
|
||||
)).done([=, channel = channel()](
|
||||
const MTPstats_PublicForwards &tlForwards) {
|
||||
using Messages = QVector<Data::RecentPostId>;
|
||||
_requestId = 0;
|
||||
|
||||
const auto &data = tlForwards.data();
|
||||
|
||||
channel->owner().processUsers(data.vusers());
|
||||
channel->owner().processChats(data.vchats());
|
||||
|
||||
const auto nextToken = Data::PublicForwardsSlice::OffsetToken({
|
||||
.storyOffset = data.vnext_offset().value_or_empty(),
|
||||
});
|
||||
|
||||
const auto allLoaded = nextToken.storyOffset.isEmpty()
|
||||
|| (nextToken.storyOffset == token.storyOffset);
|
||||
const auto fullCount = data.vcount().v;
|
||||
|
||||
auto recentList = Messages();
|
||||
for (const auto &tlForward : data.vforwards().v) {
|
||||
tlForward.match([&](const MTPDpublicForwardMessage &data) {
|
||||
const auto &message = data.vmessage();
|
||||
const auto msgId = IdFromMessage(message);
|
||||
const auto peerId = PeerFromMessage(message);
|
||||
const auto lastDate = DateFromMessage(message);
|
||||
if (const auto peer = channel->owner().peerLoaded(peerId)) {
|
||||
if (!lastDate) {
|
||||
return;
|
||||
}
|
||||
channel->owner().addNewMessage(
|
||||
message,
|
||||
MessageFlags(),
|
||||
NewMessageType::Existing);
|
||||
recentList.push_back({ .messageId = { peerId, msgId } });
|
||||
}
|
||||
}, [&](const MTPDpublicForwardStory &data) {
|
||||
data.vstory().match([&](const MTPDstoryItem &d) {
|
||||
recentList.push_back({
|
||||
.storyId = { peerFromMTP(data.vpeer()), d.vid().v }
|
||||
});
|
||||
}, [](const auto &) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_lastTotal = std::max(_lastTotal, fullCount);
|
||||
done({
|
||||
.list = std::move(recentList),
|
||||
.total = _lastTotal,
|
||||
.allLoaded = allLoaded,
|
||||
.token = nextToken,
|
||||
});
|
||||
}).fail([=] {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
MessageStatistics::MessageStatistics(
|
||||
not_null<ChannelData*> channel,
|
||||
FullMsgId fullId)
|
||||
: StatisticsRequestSender(channel)
|
||||
, _publicForwards(channel, fullId)
|
||||
, _publicForwards(channel, { .messageId = fullId })
|
||||
, _fullId(fullId) {
|
||||
}
|
||||
|
||||
MessageStatistics::MessageStatistics(
|
||||
not_null<ChannelData*> channel,
|
||||
FullStoryId storyId)
|
||||
: StatisticsRequestSender(channel)
|
||||
, _publicForwards(channel, { .storyId = storyId })
|
||||
, _storyId(storyId) {
|
||||
}
|
||||
|
||||
Data::PublicForwardsSlice MessageStatistics::firstSlice() const {
|
||||
return _firstSlice;
|
||||
}
|
||||
|
@ -438,21 +552,26 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
|||
}
|
||||
const auto requestFirstPublicForwards = [=](
|
||||
const Data::StatisticalGraph &messageGraph,
|
||||
const Data::StatisticalGraph &reactionsGraph,
|
||||
const Data::StatisticsMessageInteractionInfo &info) {
|
||||
_publicForwards.request({}, [=](Data::PublicForwardsSlice slice) {
|
||||
const auto callback = [=](Data::PublicForwardsSlice slice) {
|
||||
const auto total = slice.total;
|
||||
_firstSlice = std::move(slice);
|
||||
done({
|
||||
.messageInteractionGraph = messageGraph,
|
||||
.reactionsByEmotionGraph = reactionsGraph,
|
||||
.publicForwards = total,
|
||||
.privateForwards = info.forwardsCount - total,
|
||||
.views = info.viewsCount,
|
||||
.reactions = info.reactionsCount,
|
||||
});
|
||||
});
|
||||
};
|
||||
_publicForwards.request({}, callback);
|
||||
};
|
||||
|
||||
const auto requestPrivateForwards = [=](
|
||||
const Data::StatisticalGraph &messageGraph) {
|
||||
const Data::StatisticalGraph &messageGraph,
|
||||
const Data::StatisticalGraph &reactionsGraph) {
|
||||
api().request(MTPchannels_GetMessages(
|
||||
channel()->inputChannel,
|
||||
MTP_vector<MTPInputMessage>(
|
||||
|
@ -462,6 +581,13 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
|||
const auto process = [&](const MTPVector<MTPMessage> &messages) {
|
||||
const auto &message = messages.v.front();
|
||||
return message.match([&](const MTPDmessage &data) {
|
||||
auto reactionsCount = 0;
|
||||
if (const auto tlReactions = data.vreactions()) {
|
||||
const auto &tlCounts = tlReactions->data().vresults();
|
||||
for (const auto &tlCount : tlCounts.v) {
|
||||
reactionsCount += tlCount.data().vcount().v;
|
||||
}
|
||||
}
|
||||
return Data::StatisticsMessageInteractionInfo{
|
||||
.messageId = IdFromMessage(message),
|
||||
.viewsCount = data.vviews()
|
||||
|
@ -470,6 +596,7 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
|||
.forwardsCount = data.vforwards()
|
||||
? data.vforwards()->v
|
||||
: 0,
|
||||
.reactionsCount = reactionsCount,
|
||||
};
|
||||
}, [](const MTPDmessageEmpty &) {
|
||||
return Data::StatisticsMessageInteractionInfo();
|
||||
|
@ -488,22 +615,74 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
|||
return Data::StatisticsMessageInteractionInfo();
|
||||
});
|
||||
|
||||
requestFirstPublicForwards(messageGraph, std::move(info));
|
||||
requestFirstPublicForwards(
|
||||
messageGraph,
|
||||
reactionsGraph,
|
||||
std::move(info));
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
requestFirstPublicForwards(messageGraph, {});
|
||||
requestFirstPublicForwards(messageGraph, reactionsGraph, {});
|
||||
}).send();
|
||||
};
|
||||
|
||||
makeRequest(MTPstats_GetMessageStats(
|
||||
MTP_flags(MTPstats_GetMessageStats::Flags(0)),
|
||||
channel()->inputChannel,
|
||||
MTP_int(_fullId.msg.bare)
|
||||
)).done([=](const MTPstats_MessageStats &result) {
|
||||
requestPrivateForwards(
|
||||
StatisticalGraphFromTL(result.data().vviews_graph()));
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
requestPrivateForwards({});
|
||||
}).send();
|
||||
const auto requestStoryPrivateForwards = [=](
|
||||
const Data::StatisticalGraph &messageGraph,
|
||||
const Data::StatisticalGraph &reactionsGraph) {
|
||||
api().request(MTPstories_GetStoriesByID(
|
||||
channel()->input,
|
||||
MTP_vector<MTPint>(1, MTP_int(_storyId.story)))
|
||||
).done([=](const MTPstories_Stories &result) {
|
||||
const auto &storyItem = result.data().vstories().v.front();
|
||||
auto info = storyItem.match([&](const MTPDstoryItem &data) {
|
||||
if (!data.vviews()) {
|
||||
return Data::StatisticsMessageInteractionInfo();
|
||||
}
|
||||
const auto &tlViews = data.vviews()->data();
|
||||
return Data::StatisticsMessageInteractionInfo{
|
||||
.storyId = data.vid().v,
|
||||
.viewsCount = tlViews.vviews_count().v,
|
||||
.forwardsCount = tlViews.vforwards_count().value_or(0),
|
||||
.reactionsCount = tlViews.vreactions_count().value_or(0),
|
||||
};
|
||||
}, [](const auto &) {
|
||||
return Data::StatisticsMessageInteractionInfo();
|
||||
});
|
||||
|
||||
requestFirstPublicForwards(
|
||||
messageGraph,
|
||||
reactionsGraph,
|
||||
std::move(info));
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
requestFirstPublicForwards(messageGraph, reactionsGraph, {});
|
||||
}).send();
|
||||
};
|
||||
|
||||
if (_storyId) {
|
||||
makeRequest(MTPstats_GetStoryStats(
|
||||
MTP_flags(MTPstats_GetStoryStats::Flags(0)),
|
||||
channel()->input,
|
||||
MTP_int(_storyId.story)
|
||||
)).done([=](const MTPstats_StoryStats &result) {
|
||||
const auto &data = result.data();
|
||||
requestStoryPrivateForwards(
|
||||
StatisticalGraphFromTL(data.vviews_graph()),
|
||||
StatisticalGraphFromTL(data.vreactions_by_emotion_graph()));
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
requestStoryPrivateForwards({}, {});
|
||||
}).send();
|
||||
} else {
|
||||
makeRequest(MTPstats_GetMessageStats(
|
||||
MTP_flags(MTPstats_GetMessageStats::Flags(0)),
|
||||
channel()->inputChannel,
|
||||
MTP_int(_fullId.msg.bare)
|
||||
)).done([=](const MTPstats_MessageStats &result) {
|
||||
const auto &data = result.data();
|
||||
requestPrivateForwards(
|
||||
StatisticalGraphFromTL(data.vviews_graph()),
|
||||
StatisticalGraphFromTL(data.vreactions_by_emotion_graph()));
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
requestPrivateForwards({}, {});
|
||||
}).send();
|
||||
}
|
||||
}
|
||||
|
||||
Boosts::Boosts(not_null<PeerData*> peer)
|
||||
|
|
|
@ -68,14 +68,23 @@ private:
|
|||
|
||||
class PublicForwards final : public StatisticsRequestSender {
|
||||
public:
|
||||
PublicForwards(not_null<ChannelData*> channel, FullMsgId fullId);
|
||||
PublicForwards(
|
||||
not_null<ChannelData*> channel,
|
||||
Data::RecentPostId fullId);
|
||||
|
||||
void request(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done);
|
||||
|
||||
private:
|
||||
const FullMsgId _fullId;
|
||||
void requestMessage(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done);
|
||||
void requestStory(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done);
|
||||
|
||||
const Data::RecentPostId _fullId;
|
||||
mtpRequestId _requestId = 0;
|
||||
int _lastTotal = 0;
|
||||
|
||||
|
@ -86,6 +95,9 @@ public:
|
|||
explicit MessageStatistics(
|
||||
not_null<ChannelData*> channel,
|
||||
FullMsgId fullId);
|
||||
explicit MessageStatistics(
|
||||
not_null<ChannelData*> channel,
|
||||
FullStoryId storyId);
|
||||
|
||||
void request(Fn<void(Data::MessageStatistics)> done);
|
||||
|
||||
|
@ -94,6 +106,7 @@ public:
|
|||
private:
|
||||
PublicForwards _publicForwards;
|
||||
const FullMsgId _fullId;
|
||||
const FullStoryId _storyId;
|
||||
|
||||
Data::PublicForwardsSlice _firstSlice;
|
||||
|
||||
|
|
|
@ -7,13 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "api/api_transcribes.h"
|
||||
|
||||
#include "history/history_item.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
|
@ -22,6 +25,44 @@ Transcribes::Transcribes(not_null<ApiWrap*> api)
|
|||
, _api(&api->instance()) {
|
||||
}
|
||||
|
||||
bool Transcribes::trialsSupport() {
|
||||
if (!_trialsSupport) {
|
||||
const auto count = _session->account().appConfig().get<int>(
|
||||
u"transcribe_audio_trial_weekly_number"_q,
|
||||
0);
|
||||
const auto until = _session->account().appConfig().get<int>(
|
||||
u"transcribe_audio_trial_cooldown_until"_q,
|
||||
0);
|
||||
_trialsSupport = (count > 0) || (until > 0);
|
||||
}
|
||||
return *_trialsSupport;
|
||||
}
|
||||
|
||||
TimeId Transcribes::trialsRefreshAt() {
|
||||
if (_trialsRefreshAt < 0) {
|
||||
_trialsRefreshAt = _session->account().appConfig().get<int>(
|
||||
u"transcribe_audio_trial_cooldown_until"_q,
|
||||
0);
|
||||
}
|
||||
return _trialsRefreshAt;
|
||||
}
|
||||
|
||||
int Transcribes::trialsCount() {
|
||||
if (_trialsCount < 0) {
|
||||
_trialsCount = _session->account().appConfig().get<int>(
|
||||
u"transcribe_audio_trial_weekly_number"_q,
|
||||
-1);
|
||||
return std::max(_trialsCount, 0);
|
||||
}
|
||||
return _trialsCount;
|
||||
}
|
||||
|
||||
crl::time Transcribes::trialsMaxLengthMs() const {
|
||||
return 1000 * _session->account().appConfig().get<int>(
|
||||
u"transcribe_audio_trial_duration_max"_q,
|
||||
300);
|
||||
}
|
||||
|
||||
void Transcribes::toggle(not_null<HistoryItem*> item) {
|
||||
const auto id = item->fullId();
|
||||
auto i = _map.find(id);
|
||||
|
@ -86,6 +127,23 @@ void Transcribes::load(not_null<HistoryItem*> item) {
|
|||
MTP_int(item->id)
|
||||
)).done([=](const MTPmessages_TranscribedAudio &result) {
|
||||
const auto &data = result.data();
|
||||
|
||||
{
|
||||
const auto trialsCountChanged = data.vtrial_remains_num()
|
||||
&& (_trialsCount != data.vtrial_remains_num()->v);
|
||||
if (trialsCountChanged) {
|
||||
_trialsCount = data.vtrial_remains_num()->v;
|
||||
}
|
||||
const auto refreshAtChanged = data.vtrial_remains_until_date()
|
||||
&& (_trialsRefreshAt != data.vtrial_remains_until_date()->v);
|
||||
if (refreshAtChanged) {
|
||||
_trialsRefreshAt = data.vtrial_remains_until_date()->v;
|
||||
}
|
||||
if (trialsCountChanged) {
|
||||
ShowTrialTranscribesToast(_trialsCount, _trialsRefreshAt);
|
||||
}
|
||||
}
|
||||
|
||||
auto &entry = _map[id];
|
||||
entry.requestId = 0;
|
||||
entry.pending = data.is_pending();
|
||||
|
|
|
@ -36,12 +36,21 @@ public:
|
|||
|
||||
void apply(const MTPDupdateTranscribedAudio &update);
|
||||
|
||||
[[nodiscard]] bool trialsSupport();
|
||||
[[nodiscard]] TimeId trialsRefreshAt();
|
||||
[[nodiscard]] int trialsCount();
|
||||
[[nodiscard]] crl::time trialsMaxLengthMs() const;
|
||||
|
||||
private:
|
||||
void load(not_null<HistoryItem*> item);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
|
||||
int _trialsCount = -1;
|
||||
std::optional<bool> _trialsSupport;
|
||||
TimeId _trialsRefreshAt = -1;
|
||||
|
||||
base::flat_map<FullMsgId, Entry> _map;
|
||||
base::flat_map<uint64, FullMsgId> _ids;
|
||||
|
||||
|
|
|
@ -2023,6 +2023,19 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updatePeerWallpaper: {
|
||||
const auto &d = update.c_updatePeerWallpaper();
|
||||
if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer()))) {
|
||||
if (const auto paper = d.vwallpaper()) {
|
||||
peer->setWallPaper(
|
||||
Data::WallPaper::Create(&session(), *paper),
|
||||
d.is_wallpaper_overridden());
|
||||
} else {
|
||||
peer->setWallPaper({});
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateBotCommands: {
|
||||
const auto &d = update.c_updateBotCommands();
|
||||
if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer()))) {
|
||||
|
@ -2358,6 +2371,14 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateChannelViewForumAsMessages: {
|
||||
const auto &d = update.c_updateChannelViewForumAsMessages();
|
||||
const auto id = ChannelId(d.vchannel_id());
|
||||
if (const auto channel = session().data().channelLoaded(id)) {
|
||||
channel->setViewAsMessagesFlag(mtpIsTrue(d.venabled()));
|
||||
}
|
||||
} break;
|
||||
|
||||
// Pinned message.
|
||||
case mtpc_updatePinnedMessages: {
|
||||
const auto &d = update.c_updatePinnedMessages();
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_hash.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "api/api_media.h"
|
||||
#include "api/api_peer_colors.h"
|
||||
#include "api/api_peer_photo.h"
|
||||
#include "api/api_polls.h"
|
||||
#include "api/api_sending.h"
|
||||
|
@ -33,50 +34,35 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_user_names.h"
|
||||
#include "api/api_websites.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_drafts.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_sparse_ids.h"
|
||||
#include "data/data_search_controller.h"
|
||||
#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"
|
||||
#include "data/data_cloud_themes.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_wall_paper.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "core/application.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/random.h"
|
||||
#include "base/qt/qt_common_adapters.h"
|
||||
#include "base/call_delayed.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwindow.h"
|
||||
#include "mainwidget.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "main/main_account.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
@ -87,7 +73,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/message_field.h"
|
||||
#include "ui/item_text_options.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "support/support_helper.h"
|
||||
|
@ -95,9 +80,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "storage/localimageloader.h"
|
||||
#include "storage/download_manager_mtproto.h"
|
||||
#include "storage/file_upload.h"
|
||||
#include "storage/storage_facade.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
#include "storage/storage_media_prepare.h"
|
||||
#include "storage/storage_account.h"
|
||||
|
||||
// AyuGram includes
|
||||
|
@ -151,6 +133,15 @@ void ShowChannelsLimitBox(not_null<PeerData*> peer) {
|
|||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] FileLoadTo FileLoadTaskOptions(const Api::SendAction &action) {
|
||||
const auto peer = action.history->peer;
|
||||
return FileLoadTo(
|
||||
peer->id,
|
||||
action.options,
|
||||
action.replyTo,
|
||||
action.replaceMediaOf);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||
|
@ -184,7 +175,8 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
|||
, _transcribes(std::make_unique<Api::Transcribes>(this))
|
||||
, _premium(std::make_unique<Api::Premium>(this))
|
||||
, _usernames(std::make_unique<Api::Usernames>(this))
|
||||
, _websites(std::make_unique<Api::Websites>(this)) {
|
||||
, _websites(std::make_unique<Api::Websites>(this))
|
||||
, _peerColors(std::make_unique<Api::PeerColors>(this)) {
|
||||
crl::on_main(session, [=] {
|
||||
// You can't use _session->lifetime() in the constructor,
|
||||
// only queued, because it is not constructed yet.
|
||||
|
@ -1754,6 +1746,10 @@ void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
|
|||
}).send();
|
||||
|
||||
_channelAmInRequests.emplace(channel, requestId);
|
||||
|
||||
using Flag = ChannelDataFlag;
|
||||
chatParticipants().loadSimilarChannels(channel);
|
||||
channel->setFlags(channel->flags() | Flag::SimilarExpanded);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2070,13 +2066,13 @@ void ApiWrap::deleteHistory(
|
|||
|
||||
void ApiWrap::applyUpdates(
|
||||
const MTPUpdates &updates,
|
||||
uint64 sentMessageRandomId) {
|
||||
uint64 sentMessageRandomId) const {
|
||||
this->updates().applyUpdates(updates, sentMessageRandomId);
|
||||
}
|
||||
|
||||
int ApiWrap::applyAffectedHistory(
|
||||
PeerData *peer,
|
||||
const MTPmessages_AffectedHistory &result) {
|
||||
const MTPmessages_AffectedHistory &result) const {
|
||||
const auto &data = result.c_messages_affectedHistory();
|
||||
if (const auto channel = peer ? peer->asChannel() : nullptr) {
|
||||
channel->ptsUpdateAndApply(data.vpts().v, data.vpts_count().v);
|
||||
|
@ -2098,7 +2094,7 @@ void ApiWrap::applyAffectedMessages(
|
|||
}
|
||||
|
||||
void ApiWrap::applyAffectedMessages(
|
||||
const MTPmessages_AffectedMessages &result) {
|
||||
const MTPmessages_AffectedMessages &result) const {
|
||||
const auto &data = result.c_messages_affectedMessages();
|
||||
updates().updateAndApply(data.vpts().v, data.vpts_count().v);
|
||||
}
|
||||
|
@ -2557,8 +2553,8 @@ void ApiWrap::refreshFileReference(
|
|||
request(MTPhelp_GetPremiumPromo());
|
||||
}, [&](Data::FileOriginStory data) {
|
||||
request(MTPstories_GetStoriesByID(
|
||||
_session->data().peer(data.peerId)->input,
|
||||
MTP_vector<MTPint>(1, MTP_int(data.storyId))));
|
||||
_session->data().peer(data.peer)->input,
|
||||
MTP_vector<MTPint>(1, MTP_int(data.story))));
|
||||
}, [&](v::null_t) {
|
||||
fail();
|
||||
});
|
||||
|
@ -3444,7 +3440,7 @@ void ApiWrap::sendVoiceMessage(
|
|||
crl::time duration,
|
||||
const SendAction &action) {
|
||||
const auto caption = TextWithTags();
|
||||
const auto to = fileLoadTaskOptions(action);
|
||||
const auto to = FileLoadTaskOptions(action);
|
||||
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
||||
&session(),
|
||||
result,
|
||||
|
@ -3462,7 +3458,7 @@ void ApiWrap::editMedia(
|
|||
if (list.files.empty()) return;
|
||||
|
||||
auto &file = list.files.front();
|
||||
const auto to = fileLoadTaskOptions(action);
|
||||
const auto to = FileLoadTaskOptions(action);
|
||||
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
||||
&session(),
|
||||
file.path,
|
||||
|
@ -3491,7 +3487,7 @@ void ApiWrap::sendFiles(
|
|||
sendMessage(std::move(message));
|
||||
}
|
||||
|
||||
const auto to = fileLoadTaskOptions(action);
|
||||
const auto to = FileLoadTaskOptions(action);
|
||||
if (album) {
|
||||
album->options = to.options;
|
||||
}
|
||||
|
@ -3530,7 +3526,7 @@ void ApiWrap::sendFile(
|
|||
const QByteArray &fileContent,
|
||||
SendMediaType type,
|
||||
const SendAction &action) {
|
||||
const auto to = fileLoadTaskOptions(action);
|
||||
const auto to = FileLoadTaskOptions(action);
|
||||
auto caption = TextWithTags();
|
||||
const auto spoiler = false;
|
||||
const auto information = nullptr;
|
||||
|
@ -4227,15 +4223,6 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
|||
});
|
||||
}
|
||||
|
||||
FileLoadTo ApiWrap::fileLoadTaskOptions(const SendAction &action) const {
|
||||
const auto peer = action.history->peer;
|
||||
return FileLoadTo(
|
||||
peer->id,
|
||||
action.options,
|
||||
action.replyTo,
|
||||
action.replaceMediaOf);
|
||||
}
|
||||
|
||||
void ApiWrap::reloadContactSignupSilent() {
|
||||
if (_contactSignupSilentRequestId) {
|
||||
return;
|
||||
|
@ -4451,3 +4438,7 @@ Api::Usernames &ApiWrap::usernames() {
|
|||
Api::Websites &ApiWrap::websites() {
|
||||
return *_websites;
|
||||
}
|
||||
|
||||
Api::PeerColors &ApiWrap::peerColors() {
|
||||
return *_peerColors;
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "api/api_common.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/flat_map.h"
|
||||
#include "base/flat_set.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "data/stickers/data_stickers_set.h"
|
||||
#include "data/data_messages.h"
|
||||
|
@ -73,6 +71,7 @@ class InviteLinks;
|
|||
class ViewsManager;
|
||||
class ConfirmPhone;
|
||||
class PeerPhoto;
|
||||
class PeerColors;
|
||||
class Polls;
|
||||
class ChatParticipants;
|
||||
class UnreadThings;
|
||||
|
@ -141,10 +140,10 @@ public:
|
|||
|
||||
void applyUpdates(
|
||||
const MTPUpdates &updates,
|
||||
uint64 sentMessageRandomId = 0);
|
||||
uint64 sentMessageRandomId = 0) const;
|
||||
int applyAffectedHistory(
|
||||
PeerData *peer, // May be nullptr, like for deletePhoneCallHistory.
|
||||
const MTPmessages_AffectedHistory &result);
|
||||
const MTPmessages_AffectedHistory &result) const;
|
||||
|
||||
void registerModifyRequest(const QString &key, mtpRequestId requestId);
|
||||
void clearModifyRequest(const QString &key);
|
||||
|
@ -392,6 +391,7 @@ public:
|
|||
[[nodiscard]] Api::Premium &premium();
|
||||
[[nodiscard]] Api::Usernames &usernames();
|
||||
[[nodiscard]] Api::Websites &websites();
|
||||
[[nodiscard]] Api::PeerColors &peerColors();
|
||||
|
||||
void updatePrivacyLastSeens();
|
||||
|
||||
|
@ -503,7 +503,7 @@ private:
|
|||
not_null<PeerData*> peer,
|
||||
bool justClear,
|
||||
bool revoke);
|
||||
void applyAffectedMessages(const MTPmessages_AffectedMessages &result);
|
||||
void applyAffectedMessages(const MTPmessages_AffectedMessages &result) const;
|
||||
|
||||
void deleteAllFromParticipantSend(
|
||||
not_null<ChannelData*> channel,
|
||||
|
@ -532,7 +532,6 @@ private:
|
|||
Api::SendOptions options,
|
||||
uint64 randomId,
|
||||
Fn<void(bool)> done = nullptr);
|
||||
FileLoadTo fileLoadTaskOptions(const SendAction &action) const;
|
||||
|
||||
void getTopPromotionDelayed(TimeId now, TimeId next);
|
||||
void topPromotionDone(const MTPhelp_PromoData &proxy);
|
||||
|
@ -711,6 +710,7 @@ private:
|
|||
const std::unique_ptr<Api::Premium> _premium;
|
||||
const std::unique_ptr<Api::Usernames> _usernames;
|
||||
const std::unique_ptr<Api::Websites> _websites;
|
||||
const std::unique_ptr<Api::PeerColors> _peerColors;
|
||||
|
||||
mtpRequestId _wallPaperRequestId = 0;
|
||||
QString _wallPaperSlug;
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
namespace Ui {
|
||||
class LinkButton;
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/call_delayed.h"
|
||||
#include "base/random.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/peers/add_participants_box.h"
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "base/timer.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "main/main_session_settings.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_auto_download.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
|
@ -35,7 +36,6 @@ not_null<int64*> AddSizeLimitSlider(
|
|||
not_null<Ui::VerticalLayout*> container,
|
||||
const base::flat_map<Type, int64> &values,
|
||||
int64 defaultValue) {
|
||||
using namespace Settings;
|
||||
using Pair = base::flat_map<Type, int64>::value_type;
|
||||
|
||||
const auto limits = Ui::CreateChild<rpl::event_stream<int64>>(
|
||||
|
@ -46,7 +46,7 @@ not_null<int64*> AddSizeLimitSlider(
|
|||
[](Pair pair) { return pair.second; })->second;
|
||||
const auto startLimit = currentLimit ? currentLimit : defaultValue;
|
||||
const auto result = Ui::CreateChild<int64>(container.get(), startLimit);
|
||||
AddButtonWithLabel(
|
||||
Settings::AddButtonWithLabel(
|
||||
container,
|
||||
tr::lng_media_size_limit(),
|
||||
limits->events_starting_with_copy(
|
||||
|
@ -109,11 +109,11 @@ void AutoDownloadBox::setupContent() {
|
|||
Type type,
|
||||
rpl::producer<QString> label) {
|
||||
const auto value = settings->bytesLimit(_source, type);
|
||||
AddButton(
|
||||
content->add(object_ptr<Ui::SettingsButton>(
|
||||
content,
|
||||
std::move(label),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
))->toggleOn(
|
||||
rpl::single(value > 0)
|
||||
)->toggledChanges(
|
||||
) | rpl::start_with_next([=](bool enabled) {
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
namespace Ui {
|
||||
class Radiobutton;
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/chat/attach/attach_extensions.h"
|
||||
#include "ui/chat/chat_theme.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
@ -24,7 +25,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_document_media.h"
|
||||
#include "boxes/background_preview_box.h"
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -165,9 +165,9 @@ void BackgroundBox::prepare() {
|
|||
auto wrap = object_ptr<Ui::VerticalLayout>(this);
|
||||
const auto container = wrap.data();
|
||||
|
||||
Settings::AddSkip(container);
|
||||
Ui::AddSkip(container);
|
||||
|
||||
const auto button = container->add(Settings::CreateButton(
|
||||
const auto button = container->add(object_ptr<Ui::SettingsButton>(
|
||||
container,
|
||||
tr::lng_settings_bg_from_file(),
|
||||
st::infoProfileButton));
|
||||
|
@ -180,8 +180,8 @@ void BackgroundBox::prepare() {
|
|||
chooseFromFile();
|
||||
});
|
||||
|
||||
Settings::AddSkip(container);
|
||||
Settings::AddDivider(container);
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddDivider(container);
|
||||
|
||||
_inner = container->add(
|
||||
object_ptr<Inner>(this, &_controller->session(), _forPeer));
|
||||
|
@ -310,7 +310,7 @@ void BackgroundBox::resetForPeer() {
|
|||
}).send();
|
||||
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
_forPeer->setWallPaper(std::nullopt);
|
||||
_forPeer->setWallPaper({});
|
||||
if (weak) {
|
||||
_controller->finishChatThemeEdit(_forPeer);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
class PeerData;
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "boxes/background_preview_box.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
|
@ -18,8 +20,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/image/image.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
|
@ -33,17 +37,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_document_media.h"
|
||||
#include "data/data_document_resolver.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/background_preview_box.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/themes/window_themes_embedded.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "storage/file_upload.h"
|
||||
#include "storage/localimageloader.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/themes/window_themes_embedded.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
@ -293,10 +295,10 @@ void BackgroundPreviewBox::createDimmingSlider(bool dark) {
|
|||
const auto equals = (dark == Window::Theme::IsNightMode());
|
||||
const auto inner = Ui::CreateChild<Ui::VerticalLayout>(_dimmingContent);
|
||||
inner->show();
|
||||
Settings::AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
inner,
|
||||
tr::lng_background_dimming(),
|
||||
style::margins(0, st::settingsSectionSkip, 0, 0),
|
||||
style::margins(0, st::defaultVerticalListSkip, 0, 0),
|
||||
equals ? nullptr : dark ? &_dark->subtitle : &_light->subtitle);
|
||||
_dimmingSlider = inner->add(
|
||||
object_ptr<Ui::MediaSlider>(
|
||||
|
@ -378,7 +380,7 @@ auto BackgroundPreviewBox::prepareOverridenStyle(bool dark)
|
|||
.box = st::defaultBox,
|
||||
.toggle = toggle,
|
||||
.slider = st::defaultContinuousSlider,
|
||||
.subtitle = st::settingsSubsectionTitle,
|
||||
.subtitle = st::defaultSubsectionTitle,
|
||||
};
|
||||
result.box.button.textFg = p->lightButtonFg();
|
||||
result.box.button.textFgOver = p->lightButtonFgOver();
|
||||
|
@ -510,6 +512,10 @@ void BackgroundPreviewBox::recreateBlurCheckbox() {
|
|||
}, _blur->lifetime());
|
||||
|
||||
_blur->setDisabled(_paper.document() && _full.isNull());
|
||||
|
||||
if (_forBothOverlay) {
|
||||
_forBothOverlay->raise();
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::apply() {
|
||||
|
@ -520,7 +526,7 @@ void BackgroundPreviewBox::apply() {
|
|||
}
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::uploadForPeer() {
|
||||
void BackgroundPreviewBox::uploadForPeer(bool both) {
|
||||
Expects(_forPeer != nullptr);
|
||||
|
||||
if (_uploadId) {
|
||||
|
@ -579,7 +585,7 @@ void BackgroundPreviewBox::uploadForPeer() {
|
|||
"Got wallPaperNoFile after account.UploadWallPaper."));
|
||||
});
|
||||
if (const auto paper = Data::WallPaper::Create(session, result)) {
|
||||
setExistingForPeer(*paper);
|
||||
setExistingForPeer(*paper, both);
|
||||
}
|
||||
}).send();
|
||||
}, _uploadLifetime);
|
||||
|
@ -588,7 +594,9 @@ void BackgroundPreviewBox::uploadForPeer() {
|
|||
_radial.start(_uploadProgress);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::setExistingForPeer(const Data::WallPaper &paper) {
|
||||
void BackgroundPreviewBox::setExistingForPeer(
|
||||
const Data::WallPaper &paper,
|
||||
bool both) {
|
||||
Expects(_forPeer != nullptr);
|
||||
|
||||
if (const auto already = _forPeer->wallPaper()) {
|
||||
|
@ -602,6 +610,7 @@ void BackgroundPreviewBox::setExistingForPeer(const Data::WallPaper &paper) {
|
|||
api->request(MTPmessages_SetChatWallPaper(
|
||||
MTP_flags((_fromMessageId ? Flag::f_id : Flag())
|
||||
| (_fromMessageId ? Flag() : Flag::f_wallpaper)
|
||||
| (both ? Flag::f_for_both : Flag())
|
||||
| Flag::f_settings),
|
||||
_forPeer->input,
|
||||
paper.mtpInput(&_controller->session()),
|
||||
|
@ -618,10 +627,117 @@ void BackgroundPreviewBox::setExistingForPeer(const Data::WallPaper &paper) {
|
|||
void BackgroundPreviewBox::applyForPeer() {
|
||||
Expects(_forPeer != nullptr);
|
||||
|
||||
if (Data::IsCustomWallPaper(_paper)) {
|
||||
uploadForPeer();
|
||||
if (!Data::IsCustomWallPaper(_paper)) {
|
||||
if (const auto already = _forPeer->wallPaper()) {
|
||||
if (already->equals(_paper)) {
|
||||
_controller->finishChatThemeEdit(_forPeer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_fromMessageId && _forPeer->session().premiumPossible()) {
|
||||
if (_forBothOverlay) {
|
||||
return;
|
||||
}
|
||||
const auto size = this->size() * style::DevicePixelRatio();
|
||||
const auto bg = Images::DitherImage(
|
||||
Images::BlurLargeImage(
|
||||
Ui::GrabWidgetToImage(this).scaled(
|
||||
size / style::ConvertScale(4),
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation),
|
||||
24).scaled(
|
||||
size,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation));
|
||||
|
||||
_forBothOverlay = std::make_unique<Ui::FadeWrap<>>(
|
||||
this,
|
||||
object_ptr<Ui::RpWidget>(this));
|
||||
const auto overlay = _forBothOverlay->entity();
|
||||
|
||||
sizeValue() | rpl::start_with_next([=](QSize size) {
|
||||
_forBothOverlay->setGeometry({ QPoint(), size });
|
||||
overlay->setGeometry({ QPoint(), size });
|
||||
}, _forBothOverlay->lifetime());
|
||||
|
||||
overlay->paintRequest(
|
||||
) | rpl::start_with_next([=](QRect clip) {
|
||||
auto p = QPainter(overlay);
|
||||
p.drawImage(0, 0, bg);
|
||||
p.fillRect(clip, QColor(0, 0, 0, 64));
|
||||
}, overlay->lifetime());
|
||||
|
||||
using namespace Ui;
|
||||
const auto forMe = CreateChild<RoundButton>(
|
||||
overlay,
|
||||
tr::lng_background_apply_me(),
|
||||
st::backgroundConfirm);
|
||||
forMe->setClickedCallback([=] {
|
||||
applyForPeer(false);
|
||||
});
|
||||
using namespace rpl::mappers;
|
||||
const auto forBoth = ::Settings::CreateLockedButton(
|
||||
overlay,
|
||||
tr::lng_background_apply_both(
|
||||
lt_user,
|
||||
rpl::single(_forPeer->shortName())),
|
||||
st::backgroundConfirm,
|
||||
Data::AmPremiumValue(&_forPeer->session()) | rpl::map(!_1));
|
||||
forBoth->setClickedCallback([=] {
|
||||
if (_forPeer->session().premium()) {
|
||||
applyForPeer(true);
|
||||
} else {
|
||||
ShowPremiumPreviewBox(
|
||||
_controller->uiShow(),
|
||||
PremiumPreview::Wallpapers);
|
||||
}
|
||||
});
|
||||
const auto cancel = CreateChild<RoundButton>(
|
||||
overlay,
|
||||
tr::lng_cancel(),
|
||||
st::backgroundConfirmCancel);
|
||||
cancel->setClickedCallback([=] {
|
||||
const auto raw = _forBothOverlay.release();
|
||||
raw->shownValue() | rpl::filter(
|
||||
!rpl::mappers::_1
|
||||
) | rpl::take(1) | rpl::start_with_next(crl::guard(raw, [=] {
|
||||
delete raw;
|
||||
}), raw->lifetime());
|
||||
raw->toggle(false, anim::type::normal);
|
||||
});
|
||||
forMe->setTextTransform(RoundButton::TextTransform::NoTransform);
|
||||
forBoth->setTextTransform(RoundButton::TextTransform::NoTransform);
|
||||
cancel->setTextTransform(RoundButton::TextTransform::NoTransform);
|
||||
|
||||
overlay->sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
const auto padding = st::backgroundConfirmPadding;
|
||||
const auto width = size.width()
|
||||
- padding.left()
|
||||
- padding.right();
|
||||
const auto height = cancel->height();
|
||||
auto top = size.height() - padding.bottom() - height;
|
||||
cancel->setGeometry(padding.left(), top, width, height);
|
||||
top -= height + padding.top();
|
||||
forBoth->setGeometry(padding.left(), top, width, height);
|
||||
top -= height + padding.top();
|
||||
forMe->setGeometry(padding.left(), top, width, height);
|
||||
}, _forBothOverlay->lifetime());
|
||||
|
||||
_forBothOverlay->hide(anim::type::instant);
|
||||
_forBothOverlay->show(anim::type::normal);
|
||||
} else {
|
||||
setExistingForPeer(_paper);
|
||||
applyForPeer(false);
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::applyForPeer(bool both) {
|
||||
if (Data::IsCustomWallPaper(_paper)) {
|
||||
uploadForPeer(both);
|
||||
} else {
|
||||
setExistingForPeer(_paper, both);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "base/binary_guard.h"
|
||||
#include "history/admin_log/history_admin_log_item.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
|
@ -29,6 +29,8 @@ class ChatStyle;
|
|||
class MediaSlider;
|
||||
template <typename Widget>
|
||||
class SlideWrap;
|
||||
template <typename Widget>
|
||||
class FadeWrap;
|
||||
} // namespace Ui
|
||||
|
||||
struct BackgroundPreviewArgs {
|
||||
|
@ -66,9 +68,10 @@ private:
|
|||
|
||||
void apply();
|
||||
void applyForPeer();
|
||||
void applyForPeer(bool both);
|
||||
void applyForEveryone();
|
||||
void uploadForPeer();
|
||||
void setExistingForPeer(const Data::WallPaper &paper);
|
||||
void uploadForPeer(bool both);
|
||||
void setExistingForPeer(const Data::WallPaper &paper, bool both);
|
||||
void share();
|
||||
void radialAnimationCallback(crl::time now);
|
||||
QRect radialRect() const;
|
||||
|
@ -131,6 +134,8 @@ private:
|
|||
float64 _uploadProgress = 0.;
|
||||
rpl::lifetime _uploadLifetime;
|
||||
|
||||
std::unique_ptr<Ui::FadeWrap<Ui::RpWidget>> _forBothOverlay;
|
||||
|
||||
rpl::variable<QColor> _paletteServiceBg;
|
||||
rpl::lifetime _serviceBgLifetime;
|
||||
|
||||
|
|
|
@ -753,7 +753,28 @@ backgroundCheck: ServiceCheck {
|
|||
color: msgServiceFg;
|
||||
duration: 200;
|
||||
}
|
||||
backgroundConfirmPadding: margins(24px, 16px, 24px, 16px);
|
||||
backgroundConfirm: RoundButton(defaultActiveButton) {
|
||||
height: 44px;
|
||||
textTop: 12px;
|
||||
font: font(13px semibold);
|
||||
}
|
||||
backgroundConfirmCancel: RoundButton(backgroundConfirm) {
|
||||
textFg: mediaviewSaveMsgFg;
|
||||
textFgOver: mediaviewSaveMsgFg;
|
||||
numbersTextFg: mediaviewSaveMsgFg;
|
||||
numbersTextFgOver: mediaviewSaveMsgFg;
|
||||
textBg: shadowFg;
|
||||
textBgOver: shadowFg;
|
||||
|
||||
height: 44px;
|
||||
textTop: 12px;
|
||||
font: font(13px semibold);
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: shadowFg;
|
||||
}
|
||||
}
|
||||
urlAuthCheckbox: Checkbox(defaultBoxCheckbox) {
|
||||
width: 240px;
|
||||
}
|
||||
|
@ -906,6 +927,14 @@ sponsoredUrlButton: RoundButton(defaultActiveButton) {
|
|||
}
|
||||
}
|
||||
|
||||
requestPeerRestriction: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 240px;
|
||||
textFg: membersAboutLimitFg;
|
||||
style: TextStyle(boxTextStyle) {
|
||||
lineHeight: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
requestsBoxItem: PeerListItem(peerListBoxItem) {
|
||||
height: 99px;
|
||||
button: OutlineButton(defaultPeerListButton) {
|
||||
|
|
|
@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "base/timer.h"
|
||||
#include "base/object_ptr.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/core_settings_proxy.h"
|
||||
#include "mtproto/connection_abstract.h"
|
||||
#include "mtproto/mtproto_proxy_data.h"
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#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"
|
||||
|
@ -26,7 +27,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/message_field.h"
|
||||
#include "menu/menu_send.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "base/unique_qptr.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "base/call_delayed.h"
|
||||
|
@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -790,7 +789,7 @@ not_null<Ui::InputField*> CreatePollBox::setupQuestion(
|
|||
using namespace Settings;
|
||||
|
||||
const auto session = &_controller->session();
|
||||
AddSubsectionTitle(container, tr::lng_polls_create_question());
|
||||
Ui::AddSubsectionTitle(container, tr::lng_polls_create_question());
|
||||
const auto question = container->add(
|
||||
object_ptr<Ui::InputField>(
|
||||
container,
|
||||
|
@ -818,9 +817,9 @@ not_null<Ui::InputField*> CreatePollBox::setupQuestion(
|
|||
- st::createPollWarningPosition.x()),
|
||||
(geometry.y()
|
||||
- st::createPollFieldPadding.top()
|
||||
- st::settingsSubsectionTitlePadding.bottom()
|
||||
- st::settingsSubsectionTitle.style.font->height
|
||||
+ st::settingsSubsectionTitle.style.font->ascent
|
||||
- st::defaultSubsectionTitlePadding.bottom()
|
||||
- st::defaultSubsectionTitle.style.font->height
|
||||
+ st::defaultSubsectionTitle.style.font->ascent
|
||||
- st::createPollWarning.style.font->ascent),
|
||||
geometry.width());
|
||||
}, warning->lifetime());
|
||||
|
@ -841,8 +840,8 @@ not_null<Ui::InputField*> CreatePollBox::setupSolution(
|
|||
const auto inner = outer->entity();
|
||||
|
||||
const auto session = &_controller->session();
|
||||
AddSkip(inner);
|
||||
AddSubsectionTitle(inner, tr::lng_polls_solution_title());
|
||||
Ui::AddSkip(inner);
|
||||
Ui::AddSubsectionTitle(inner, tr::lng_polls_solution_title());
|
||||
const auto solution = inner->add(
|
||||
object_ptr<Ui::InputField>(
|
||||
inner,
|
||||
|
@ -875,9 +874,9 @@ not_null<Ui::InputField*> CreatePollBox::setupSolution(
|
|||
- st::createPollWarningPosition.x()),
|
||||
(geometry.y()
|
||||
- st::createPollFieldPadding.top()
|
||||
- st::settingsSubsectionTitlePadding.bottom()
|
||||
- st::settingsSubsectionTitle.style.font->height
|
||||
+ st::settingsSubsectionTitle.style.font->ascent
|
||||
- st::defaultSubsectionTitlePadding.bottom()
|
||||
- st::defaultSubsectionTitle.style.font->height
|
||||
+ st::defaultSubsectionTitle.style.font->ascent
|
||||
- st::createPollWarning.style.font->ascent),
|
||||
geometry.width());
|
||||
}, warning->lifetime());
|
||||
|
@ -902,13 +901,13 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
|||
const auto container = result.data();
|
||||
|
||||
const auto question = setupQuestion(container);
|
||||
AddDivider(container);
|
||||
AddSkip(container);
|
||||
Ui::AddDivider(container);
|
||||
Ui::AddSkip(container);
|
||||
container->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
tr::lng_polls_create_options(),
|
||||
st::settingsSubsectionTitle),
|
||||
st::defaultSubsectionTitle),
|
||||
st::createPollFieldTitlePadding);
|
||||
const auto options = lifetime().make_state<Options>(
|
||||
getDelegate()->outerContainer(),
|
||||
|
@ -939,8 +938,8 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
|||
options->focusFirst();
|
||||
}, question->lifetime());
|
||||
|
||||
AddSkip(container);
|
||||
AddSubsectionTitle(container, tr::lng_polls_create_settings());
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddSubsectionTitle(container, tr::lng_polls_create_settings());
|
||||
|
||||
const auto anonymous = (!(_disabled & PollData::Flag::PublicVotes))
|
||||
? container->add(
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "api/api_common.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "base/flags.h"
|
||||
|
|
|
@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#ifndef TDESKTOP_DISABLE_SPELLCHECK
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
|
||||
namespace ChatHelpers {
|
||||
|
|
|
@ -13,9 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "history/history.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "settings/settings_privacy_security.h"
|
||||
#include "calls/calls_instance.h"
|
||||
#include "base/binary_guard.h"
|
||||
|
@ -233,7 +233,7 @@ Ui::FlatLabel *EditPrivacyBox::addLabel(
|
|||
object_ptr<Ui::DividerLabel>(
|
||||
container,
|
||||
std::move(label),
|
||||
st::settingsDividerLabelPadding),
|
||||
st::defaultBoxDividerLabelPadding),
|
||||
{ 0, topSkip, 0, 0 });
|
||||
return result;
|
||||
}
|
||||
|
@ -294,7 +294,7 @@ void EditPrivacyBox::setupContent() {
|
|||
const auto button = content->add(
|
||||
object_ptr<Ui::SlideWrap<Button>>(
|
||||
content,
|
||||
CreateButton(
|
||||
object_ptr<Button>(
|
||||
content,
|
||||
rpl::duplicate(text),
|
||||
st::settingsButtonNoIcon)));
|
||||
|
@ -321,7 +321,7 @@ void EditPrivacyBox::setupContent() {
|
|||
content->add(std::move(above));
|
||||
}
|
||||
|
||||
AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
content,
|
||||
_controller->optionsTitleKey(),
|
||||
{ 0, st::settingsPrivacySkipTop, 0, 0 });
|
||||
|
@ -332,7 +332,7 @@ void EditPrivacyBox::setupContent() {
|
|||
const auto warning = addLabelOrDivider(
|
||||
content,
|
||||
_controller->warning(),
|
||||
st::settingsSectionSkip + st::settingsPrivacySkipTop);
|
||||
st::defaultVerticalListSkip + st::settingsPrivacySkipTop);
|
||||
if (warning) {
|
||||
_controller->prepareWarningLabel(warning);
|
||||
}
|
||||
|
@ -345,8 +345,8 @@ void EditPrivacyBox::setupContent() {
|
|||
content->add(std::move(middle));
|
||||
}
|
||||
|
||||
AddSkip(content);
|
||||
AddSubsectionTitle(
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSubsectionTitle(
|
||||
content,
|
||||
tr::lng_edit_privacy_exceptions(),
|
||||
{ 0, st::settingsPrivacySkipTop, 0, 0 });
|
||||
|
@ -355,7 +355,7 @@ void EditPrivacyBox::setupContent() {
|
|||
addLabel(
|
||||
content,
|
||||
_controller->exceptionsDescription() | Ui::Text::ToWithEntities(),
|
||||
st::settingsSectionSkip);
|
||||
st::defaultVerticalListSkip);
|
||||
|
||||
if (auto below = _controller->setupBelowWidget(_window, content)) {
|
||||
content->add(std::move(below));
|
||||
|
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/filter_icons.h"
|
||||
#include "ui/filter_icon_panel.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_peer.h"
|
||||
|
@ -515,7 +516,7 @@ not_null<Ui::SettingsButton*> AddToggledButton(
|
|||
const auto toggled = container->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::SettingsButton>>(
|
||||
container,
|
||||
CreateButton(
|
||||
CreateButtonWithIcon(
|
||||
container,
|
||||
std::move(text),
|
||||
st,
|
||||
|
@ -658,12 +659,12 @@ void EditFilterBox(
|
|||
name->setFocusFast();
|
||||
});
|
||||
|
||||
AddSkip(content);
|
||||
AddDivider(content);
|
||||
AddSkip(content);
|
||||
AddSubsectionTitle(content, tr::lng_filters_include());
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddDivider(content);
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSubsectionTitle(content, tr::lng_filters_include());
|
||||
|
||||
const auto includeAdd = AddButton(
|
||||
const auto includeAdd = AddButtonWithIcon(
|
||||
content,
|
||||
tr::lng_filters_add_chats(),
|
||||
st::settingsButtonActive,
|
||||
|
@ -676,9 +677,9 @@ void EditFilterBox(
|
|||
kTypes,
|
||||
&Data::ChatFilter::always);
|
||||
|
||||
AddSkip(content);
|
||||
AddDividerText(content, tr::lng_filters_include_about());
|
||||
AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddDividerText(content, tr::lng_filters_include_about());
|
||||
Ui::AddSkip(content);
|
||||
|
||||
auto excludeWrap = content->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
|
@ -688,9 +689,9 @@ void EditFilterBox(
|
|||
excludeWrap->toggleOn(state->chatlist.value() | rpl::map(!_1));
|
||||
const auto excludeInner = excludeWrap->entity();
|
||||
|
||||
AddSubsectionTitle(excludeInner, tr::lng_filters_exclude());
|
||||
Ui::AddSubsectionTitle(excludeInner, tr::lng_filters_exclude());
|
||||
|
||||
const auto excludeAdd = AddButton(
|
||||
const auto excludeAdd = AddButtonWithIcon(
|
||||
excludeInner,
|
||||
tr::lng_filters_remove_chats(),
|
||||
st::settingsButtonActive,
|
||||
|
@ -703,9 +704,9 @@ void EditFilterBox(
|
|||
kExcludeTypes,
|
||||
&Data::ChatFilter::never);
|
||||
|
||||
AddSkip(excludeInner);
|
||||
AddDividerText(excludeInner, tr::lng_filters_exclude_about());
|
||||
AddSkip(excludeInner);
|
||||
Ui::AddSkip(excludeInner);
|
||||
Ui::AddDividerText(excludeInner, tr::lng_filters_exclude_about());
|
||||
Ui::AddSkip(excludeInner);
|
||||
|
||||
const auto collect = [=]() -> std::optional<Data::ChatFilter> {
|
||||
const auto title = name->getLastText().trimmed();
|
||||
|
@ -726,7 +727,7 @@ void EditFilterBox(
|
|||
return rules.withTitle(title);
|
||||
};
|
||||
|
||||
AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
content,
|
||||
rpl::conditional(
|
||||
state->hasLinks.value(),
|
||||
|
@ -806,8 +807,8 @@ void EditFilterBox(
|
|||
}));
|
||||
}));
|
||||
}, createLink->lifetime());
|
||||
AddSkip(content);
|
||||
AddDividerText(
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddDividerText(
|
||||
content,
|
||||
rpl::conditional(
|
||||
state->hasLinks.value(),
|
||||
|
|
|
@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
@ -140,12 +141,12 @@ void ChatFilterLinkBox(
|
|||
tr::lng_group_invite_label_header(),
|
||||
data.title),
|
||||
style::margins(
|
||||
st::settingsSubsectionTitlePadding.left(),
|
||||
st::settingsSectionSkip,
|
||||
st::settingsSubsectionTitlePadding.right(),
|
||||
st::settingsSectionSkip * 2));
|
||||
st::defaultSubsectionTitlePadding.left(),
|
||||
st::defaultVerticalListSkip,
|
||||
st::defaultSubsectionTitlePadding.right(),
|
||||
st::defaultVerticalListSkip * 2));
|
||||
labelField->setMaxLength(kMaxLinkTitleLength);
|
||||
Settings::AddDivider(container);
|
||||
AddDivider(container);
|
||||
|
||||
box->setFocusCallback([=] {
|
||||
labelField->setFocusFast();
|
||||
|
@ -616,7 +617,7 @@ void LinkController::addLinkBlock(not_null<Ui::VerticalLayout*> container) {
|
|||
&st::menuIconDelete);
|
||||
return result;
|
||||
};
|
||||
AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
container,
|
||||
tr::lng_filters_link_subtitle(),
|
||||
st::filterLinkSubsectionTitlePadding);
|
||||
|
@ -637,11 +638,11 @@ void LinkController::addLinkBlock(not_null<Ui::VerticalLayout*> container) {
|
|||
|
||||
AddCopyShareLinkButtons(container, copyLink, shareLink);
|
||||
|
||||
AddSkip(container, st::inviteLinkJoinedRowPadding.bottom() * 2);
|
||||
Ui::AddSkip(container, st::inviteLinkJoinedRowPadding.bottom() * 2);
|
||||
|
||||
AddSkip(container);
|
||||
Ui::AddSkip(container);
|
||||
|
||||
AddDivider(container);
|
||||
Ui::AddDivider(container);
|
||||
}
|
||||
|
||||
void LinkController::prepare() {
|
||||
|
@ -788,7 +789,7 @@ void LinkController::setupBelowWidget() {
|
|||
? tr::lng_filters_link_chats_no_about()
|
||||
: tr::lng_filters_link_chats_about()),
|
||||
st::boxDividerLabel),
|
||||
st::settingsDividerLabelPadding));
|
||||
st::defaultBoxDividerLabelPadding));
|
||||
}
|
||||
|
||||
Main::Session &LinkController::session() const {
|
||||
|
@ -1152,7 +1153,7 @@ void AddFilterSubtitleWithToggles(
|
|||
font->width(tr::lng_filters_by_link_select(tr::now)),
|
||||
font->width(tr::lng_filters_by_link_deselect(tr::now))));
|
||||
}
|
||||
const auto title = Settings::AddSubsectionTitle(
|
||||
const auto title = Ui::AddSubsectionTitle(
|
||||
container,
|
||||
std::move(text),
|
||||
padding);
|
||||
|
|
|
@ -24,7 +24,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "boxes/translate_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
|
@ -1177,12 +1179,12 @@ void LanguageBox::setupTop(not_null<Ui::VerticalLayout*> container) {
|
|||
if (!_controller) {
|
||||
return;
|
||||
}
|
||||
const auto translateEnabled = Settings::AddButton(
|
||||
container,
|
||||
tr::lng_translate_settings_show(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(Core::App().settings().translateButtonEnabled()));
|
||||
const auto translateEnabled = container->add(
|
||||
object_ptr<Ui::SettingsButton>(
|
||||
container,
|
||||
tr::lng_translate_settings_show(),
|
||||
st::settingsButtonNoIcon))->toggleOn(
|
||||
rpl::single(Core::App().settings().translateButtonEnabled()));
|
||||
|
||||
translateEnabled->toggledValue(
|
||||
) | rpl::filter([](bool checked) {
|
||||
|
@ -1194,11 +1196,11 @@ void LanguageBox::setupTop(not_null<Ui::VerticalLayout*> container) {
|
|||
|
||||
using namespace rpl::mappers;
|
||||
auto premium = Data::AmPremiumValue(&_controller->session());
|
||||
const auto translateChat = Settings::AddButton(
|
||||
const auto translateChat = container->add(object_ptr<Ui::SettingsButton>(
|
||||
container,
|
||||
tr::lng_translate_settings_chat(),
|
||||
st::settingsButtonNoIconLocked
|
||||
)->toggleOn(rpl::merge(
|
||||
))->toggleOn(rpl::merge(
|
||||
rpl::combine(
|
||||
Core::App().settings().translateChatEnabledValue(),
|
||||
rpl::duplicate(premium),
|
||||
|
@ -1250,10 +1252,8 @@ void LanguageBox::setupTop(not_null<Ui::VerticalLayout*> container) {
|
|||
translateSkip->setClickedCallback([=] {
|
||||
uiShow()->showBox(Ui::EditSkipTranslationLanguages());
|
||||
});
|
||||
Settings::AddSkip(container);
|
||||
Settings::AddDividerText(
|
||||
container,
|
||||
tr::lng_translate_settings_about());
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddDividerText(container, tr::lng_translate_settings_about());
|
||||
}
|
||||
|
||||
void LanguageBox::keyPressEvent(QKeyEvent *e) {
|
||||
|
|
|
@ -7,8 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "base/binary_guard.h"
|
||||
|
||||
struct LanguageId;
|
||||
|
@ -37,8 +36,6 @@ protected:
|
|||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
using Languages = Lang::CloudManager::Languages;
|
||||
|
||||
void setupTop(not_null<Ui::VerticalLayout*> container);
|
||||
[[nodiscard]] int rowsInPage() const;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "boxes/local_storage_box.h"
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "storage/cache/storage_cache_database.h"
|
||||
|
||||
namespace Main {
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
class MaxInviteBox final : public Ui::BoxContent {
|
||||
public:
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
|
||||
|
|
|
@ -11,9 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/empty_userpic.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "ui/userpic_view.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "data/data_cloud_file.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
namespace style {
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/flat_set.h"
|
||||
#include "base/weak_ptr.h"
|
||||
#include "base/timer.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class History;
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "apiwrap.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -20,15 +20,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "info/profile/info_profile_icon.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h" // Session::api().
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -352,11 +352,11 @@ void ChoosePeerBoxController::prepareRestrictions() {
|
|||
const auto raw = above.data();
|
||||
auto rows = RestrictionsList(_query);
|
||||
if (!rows.empty()) {
|
||||
Settings::AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
raw,
|
||||
tr::lng_request_peer_requirements(),
|
||||
{ 0, st::membersMarginTop, 0, 0 });
|
||||
const auto skip = st::settingsSubsectionTitlePadding.left();
|
||||
const auto skip = st::defaultSubsectionTitlePadding.left();
|
||||
auto separator = QString::fromUtf8("\n\xE2\x80\xA2 ");
|
||||
raw->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
|
@ -364,7 +364,7 @@ void ChoosePeerBoxController::prepareRestrictions() {
|
|||
separator + rows.join(separator),
|
||||
st::requestPeerRestriction),
|
||||
{ skip, 0, skip, st::membersMarginTop });
|
||||
Settings::AddDivider(raw);
|
||||
Ui::AddDivider(raw);
|
||||
}
|
||||
const auto make = [&](tr::phrase<> text, const style::icon &st) {
|
||||
auto button = raw->add(
|
||||
|
|
|
@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/effects/emoji_fly_animation.h"
|
||||
#include "ui/abstract_button.h"
|
||||
#include "ui/color_int_conversion.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_forum.h"
|
||||
|
@ -32,14 +32,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "info/profile/info_profile_emoji_status_panel.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "apiwrap.h"
|
||||
#include "mainwindow.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
||||
namespace {
|
||||
namespace {
|
||||
|
||||
constexpr auto kDefaultIconId = DocumentId(0x7FFF'FFFF'FFFF'FFFFULL);
|
||||
|
@ -114,8 +112,6 @@ bool DefaultIconEmoji::readyInDefaultState() {
|
|||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
[[nodiscard]] int EditIconSize() {
|
||||
const auto tag = Data::CustomEmojiManager::SizeTag::Large;
|
||||
return Data::FrameSizeFromTag(tag) / style::DevicePixelRatio();
|
||||
|
@ -479,9 +475,7 @@ void EditForumTopicBox(
|
|||
}, title->lifetime());
|
||||
|
||||
if (!topic || !topic->isGeneral()) {
|
||||
Settings::AddDividerText(
|
||||
top,
|
||||
tr::lng_forum_choose_title_and_icon());
|
||||
Ui::AddDividerText(top, tr::lng_forum_choose_title_and_icon());
|
||||
|
||||
box->setScrollStyle(st::reactPanelScroll);
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "settings/settings_common.h" // AddButton.
|
||||
#include "data/data_changes.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::RichLangValue
|
||||
|
@ -267,8 +268,8 @@ void Controller::choose(not_null<ChatData*> chat) {
|
|||
if (!chat) {
|
||||
Assert(channel->isBroadcast());
|
||||
|
||||
Settings::AddSkip(above);
|
||||
Settings::AddButton(
|
||||
Ui::AddSkip(above);
|
||||
Settings::AddButtonWithIcon(
|
||||
above,
|
||||
tr::lng_manage_discussion_group_create(),
|
||||
st::infoCreateLinkedChatButton,
|
||||
|
@ -286,7 +287,7 @@ void Controller::choose(not_null<ChatData*> chat) {
|
|||
|
||||
auto below = object_ptr<Ui::VerticalLayout>(box);
|
||||
if (chat && canEdit) {
|
||||
Settings::AddButton(
|
||||
Settings::AddButtonWithIcon(
|
||||
below,
|
||||
(channel->isBroadcast()
|
||||
? tr::lng_manage_discussion_group_unlink
|
||||
|
@ -294,9 +295,9 @@ void Controller::choose(not_null<ChatData*> chat) {
|
|||
st::infoUnlinkChatButton,
|
||||
{ &st::menuIconRemove }
|
||||
)->addClickHandler([=] { callback(nullptr); });
|
||||
Settings::AddSkip(below);
|
||||
Ui::AddSkip(below);
|
||||
}
|
||||
Settings::AddDividerText(
|
||||
Ui::AddDividerText(
|
||||
below,
|
||||
(channel->isBroadcast()
|
||||
? tr::lng_manage_discussion_group_posted
|
||||
|
|
|
@ -13,7 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "settings/settings_common.h" // IconDescriptor.
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -45,7 +46,7 @@ namespace {
|
|||
struct State {
|
||||
rpl::event_stream<bool> toggled;
|
||||
};
|
||||
Settings::AddSkip(container);
|
||||
Ui::AddSkip(container);
|
||||
const auto state = container->lifetime().make_state<State>();
|
||||
const auto button = container->add(
|
||||
EditPeerInfoBox::CreateButton(
|
||||
|
@ -58,10 +59,8 @@ namespace {
|
|||
))->toggleOn(rpl::single(
|
||||
(megagroup->flags() & ChannelDataFlag::ParticipantsHidden) != 0
|
||||
) | rpl::then(state->toggled.events()));
|
||||
Settings::AddSkip(container);
|
||||
Settings::AddDividerText(
|
||||
container,
|
||||
tr::lng_profile_hide_participants_about());
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddDividerText(container, tr::lng_profile_hide_participants_about());
|
||||
|
||||
button->toggledValue(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "base/unique_qptr.h"
|
||||
#include "data/data_chat_participant_status.h"
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peers/edit_participants_box.h"
|
||||
|
||||
#include "api/api_chat_participants.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/edit_participant_box.h"
|
||||
#include "boxes/peers/add_participants_box.h"
|
||||
#include "boxes/peers/prepare_short_info_box.h" // PrepareShortInfoBox
|
||||
|
@ -21,7 +20,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "mtproto/mtproto_config.h"
|
||||
#include "apiwrap.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "dialogs/dialogs_indexed_list.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -33,7 +31,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#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"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "history/history.h"
|
||||
|
@ -426,9 +423,7 @@ bool ParticipantsAdditionalData::isExternal(
|
|||
|
||||
bool ParticipantsAdditionalData::isKicked(
|
||||
not_null<PeerData*> participant) const {
|
||||
return _peer->isChat()
|
||||
? false
|
||||
: _kicked.find(participant) != end(_kicked);
|
||||
return !_peer->isChat() && (_kicked.find(participant) != end(_kicked));
|
||||
}
|
||||
|
||||
UserData *ParticipantsAdditionalData::adminPromotedBy(
|
||||
|
@ -1645,6 +1640,33 @@ base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
|
|||
? &st::menuIconProfile
|
||||
: &st::menuIconInfo));
|
||||
}
|
||||
if (const auto by = _additional.restrictedBy(participant)) {
|
||||
result->addAction(
|
||||
(_role == Role::Kicked
|
||||
? tr::lng_channel_banned_status_removed_by
|
||||
: tr::lng_channel_banned_status_restricted_by)(
|
||||
tr::now,
|
||||
lt_user,
|
||||
by->name()),
|
||||
crl::guard(this, [=] {
|
||||
_navigation->parentController()->show(
|
||||
PrepareShortInfoBox(by, _navigation));
|
||||
}),
|
||||
&st::menuIconAdmin);
|
||||
} else if (user) {
|
||||
if (const auto by = _additional.adminPromotedBy(user)) {
|
||||
result->addAction(
|
||||
tr::lng_channel_admin_status_promoted_by(
|
||||
tr::now,
|
||||
lt_user,
|
||||
by->name()),
|
||||
crl::guard(this, [=] {
|
||||
_navigation->parentController()->show(
|
||||
PrepareShortInfoBox(by, _navigation));
|
||||
}),
|
||||
&st::menuIconAdmin);
|
||||
}
|
||||
}
|
||||
if (_role == Role::Kicked) {
|
||||
if (_peer->isMegagroup()
|
||||
&& _additional.canRestrictParticipant(participant)) {
|
||||
|
|
|
@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include <rpl/variable.h>
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/weak_ptr.h"
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peers/edit_peer_color_box.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_peer_colors.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/peers/replace_boost_box.h"
|
||||
#include "chat_helpers/compose/compose_show.h"
|
||||
|
@ -37,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/section_widget.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -459,15 +461,15 @@ void Set(
|
|||
).done(done).fail(fail).send();
|
||||
};
|
||||
if (peer->isSelf()) {
|
||||
using Flag = MTPaccount_UpdateColor::Flag;
|
||||
send(MTPaccount_UpdateColor(
|
||||
MTP_flags(
|
||||
MTPaccount_UpdateColor::Flag::f_background_emoji_id),
|
||||
MTP_flags(Flag::f_color | Flag::f_background_emoji_id),
|
||||
MTP_int(colorIndex),
|
||||
MTP_long(backgroundEmojiId)));
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
using Flag = MTPchannels_UpdateColor::Flag;
|
||||
send(MTPchannels_UpdateColor(
|
||||
MTP_flags(
|
||||
MTPchannels_UpdateColor::Flag::f_background_emoji_id),
|
||||
MTP_flags(Flag::f_background_emoji_id),
|
||||
channel->inputChannel,
|
||||
MTP_int(colorIndex),
|
||||
MTP_long(backgroundEmojiId)));
|
||||
|
@ -526,7 +528,7 @@ void Apply(
|
|||
show->show(Box(Ui::AskBoostBox, Ui::AskBoostBoxData{
|
||||
.link = qs(data.vboost_url()),
|
||||
.boost = counters,
|
||||
.requiredLevel = required,
|
||||
.reason = { Ui::AskBoostChannelColor{ required } },
|
||||
}, openStatistics, nullptr));
|
||||
cancel();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
|
@ -661,11 +663,10 @@ int ColorSelector::resizeGetHeight(int newWidth) {
|
|||
const auto st = parent->lifetime().make_state<style::SettingsButton>(
|
||||
basicSt);
|
||||
st->padding.setRight(rightPadding);
|
||||
auto result = CreateButton(
|
||||
auto result = object_ptr<Ui::SettingsButton>(
|
||||
parent,
|
||||
tr::lng_settings_color_emoji(),
|
||||
*st,
|
||||
{});
|
||||
*st);
|
||||
const auto raw = result.data();
|
||||
|
||||
const auto right = Ui::CreateChild<Ui::RpWidget>(raw);
|
||||
|
@ -787,19 +788,7 @@ void EditPeerColorBox(
|
|||
state->emojiId.value()
|
||||
), {});
|
||||
|
||||
const auto appConfig = &peer->session().account().appConfig();
|
||||
auto indices = rpl::single(
|
||||
rpl::empty
|
||||
) | rpl::then(
|
||||
appConfig->refreshed()
|
||||
) | rpl::map([=] {
|
||||
const auto list = appConfig->get<std::vector<int>>(
|
||||
"peer_colors_available",
|
||||
{ 0, 1, 2, 3, 4, 5, 6 });
|
||||
return list | ranges::views::transform([](int i) {
|
||||
return uint8(i);
|
||||
}) | ranges::to_vector;
|
||||
});
|
||||
auto indices = peer->session().api().peerColors().suggestedValue();
|
||||
const auto margin = st::settingsColorRadioMargin;
|
||||
const auto skip = st::settingsColorRadioSkip;
|
||||
box->addRow(
|
||||
|
@ -812,11 +801,11 @@ void EditPeerColorBox(
|
|||
{ margin, skip, margin, skip });
|
||||
|
||||
const auto container = box->verticalLayout();
|
||||
AddDividerText(container, peer->isSelf()
|
||||
Ui::AddDividerText(container, peer->isSelf()
|
||||
? tr::lng_settings_color_about()
|
||||
: tr::lng_settings_color_about_channel());
|
||||
|
||||
AddSkip(container, st::settingsColorSampleSkip);
|
||||
Ui::AddSkip(container, st::settingsColorSampleSkip);
|
||||
|
||||
container->add(CreateEmojiIconButton(
|
||||
container,
|
||||
|
@ -826,8 +815,8 @@ void EditPeerColorBox(
|
|||
state->emojiId.value(),
|
||||
[=](DocumentId id) { state->emojiId = id; }));
|
||||
|
||||
AddSkip(container, st::settingsColorSampleSkip);
|
||||
AddDividerText(container, peer->isSelf()
|
||||
Ui::AddSkip(container, st::settingsColorSampleSkip);
|
||||
Ui::AddDividerText(container, peer->isSelf()
|
||||
? tr::lng_settings_color_emoji_about()
|
||||
: tr::lng_settings_color_emoji_about_channel());
|
||||
|
||||
|
@ -853,7 +842,7 @@ void AddPeerColorButton(
|
|||
not_null<Ui::VerticalLayout*> container,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer) {
|
||||
const auto button = AddButton(
|
||||
const auto button = AddButtonWithIcon(
|
||||
container,
|
||||
(peer->isSelf()
|
||||
? tr::lng_settings_theme_name_color()
|
||||
|
|
|
@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_peer_photo.h"
|
||||
#include "api/api_user_names.h"
|
||||
#include "main/main_session.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/peers/edit_participants_box.h"
|
||||
#include "boxes/peers/edit_peer_color_box.h"
|
||||
|
@ -23,10 +22,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peers/edit_linked_chat_box.h"
|
||||
#include "boxes/peers/edit_peer_requests_box.h"
|
||||
#include "boxes/peers/edit_peer_reactions.h"
|
||||
#include "boxes/peers/replace_boost_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "boxes/username_box.h"
|
||||
#include "ui/boxes/single_choice_box.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
|
@ -37,35 +36,36 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_changes.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/admin_log/history_admin_log_section.h"
|
||||
#include "info/boosts/info_boosts_widget.h"
|
||||
#include "info/profile/info_profile_values.h"
|
||||
#include "info/info_memento.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/boxes/boost_box.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -87,13 +87,9 @@ void AddSkip(
|
|||
not_null<Ui::VerticalLayout*> container,
|
||||
int top = st::editPeerTopButtonsLayoutSkip,
|
||||
int bottom = st::editPeerTopButtonsLayoutSkipToBottom) {
|
||||
container->add(object_ptr<Ui::FixedHeightWidget>(
|
||||
container,
|
||||
top));
|
||||
container->add(object_ptr<Ui::BoxContentDivider>(container));
|
||||
container->add(object_ptr<Ui::FixedHeightWidget>(
|
||||
container,
|
||||
bottom));
|
||||
Ui::AddSkip(container, top);
|
||||
Ui::AddDivider(container);
|
||||
Ui::AddSkip(container, bottom);
|
||||
}
|
||||
|
||||
void AddButtonWithCount(
|
||||
|
@ -245,10 +241,6 @@ void ShowEditPermissions(
|
|||
navigation->parentController()->show(Box(std::move(createBox)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
|
||||
class Controller : public base::has_weak_ptr {
|
||||
public:
|
||||
Controller(
|
||||
|
@ -269,6 +261,7 @@ private:
|
|||
Ui::VerticalLayout *buttonsLayout = nullptr;
|
||||
Ui::SettingsButton *forumToggle = nullptr;
|
||||
bool forumToggleLocked = false;
|
||||
bool levelRequested = false;
|
||||
Ui::SlideWrap<> *historyVisibilityWrap = nullptr;
|
||||
};
|
||||
struct Saving {
|
||||
|
@ -318,6 +311,7 @@ private:
|
|||
void submitDescription();
|
||||
void deleteWithConfirmation();
|
||||
void deleteChannel();
|
||||
void editReactions();
|
||||
|
||||
[[nodiscard]] std::optional<Saving> validate() const;
|
||||
[[nodiscard]] bool validateUsernamesOrder(Saving &to) const;
|
||||
|
@ -591,10 +585,10 @@ object_ptr<Ui::RpWidget> Controller::createStickersEdit() {
|
|||
object_ptr<Ui::VerticalLayout>(_wrap));
|
||||
const auto container = result->entity();
|
||||
|
||||
Settings::AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
container,
|
||||
tr::lng_group_stickers(),
|
||||
{ 0, st::settingsSubsectionTitlePadding.top() - bottomSkip, 0, 0 });
|
||||
{ 0, st::defaultSubsectionTitlePadding.top() - bottomSkip, 0, 0 });
|
||||
|
||||
AddButtonWithCount(
|
||||
container,
|
||||
|
@ -606,13 +600,13 @@ object_ptr<Ui::RpWidget> Controller::createStickersEdit() {
|
|||
},
|
||||
{ &st::menuIconStickers });
|
||||
|
||||
Settings::AddSkip(container, bottomSkip);
|
||||
Ui::AddSkip(container, bottomSkip);
|
||||
|
||||
Settings::AddDividerText(
|
||||
Ui::AddDividerText(
|
||||
container,
|
||||
tr::lng_group_stickers_description());
|
||||
|
||||
Settings::AddSkip(container, bottomSkip);
|
||||
Ui::AddSkip(container, bottomSkip);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1002,12 +996,12 @@ void Controller::fillManageSection() {
|
|||
if (_isBot) {
|
||||
const auto &container = _controls.buttonsLayout;
|
||||
|
||||
AddSkip(container, 0);
|
||||
::AddSkip(container, 0);
|
||||
fillBotUsernamesButton();
|
||||
fillBotEditIntroButton();
|
||||
fillBotEditCommandsButton();
|
||||
fillBotEditSettingsButton();
|
||||
Settings::AddSkip(
|
||||
Ui::AddSkip(
|
||||
container,
|
||||
st::editPeerTopButtonsLayoutSkipCustomBottom);
|
||||
container->add(object_ptr<Ui::DividerLabel>(
|
||||
|
@ -1022,7 +1016,7 @@ void Controller::fillManageSection() {
|
|||
kBotManagerUsername.utf16()))),
|
||||
Ui::Text::RichLangValue),
|
||||
st::boxDividerLabel),
|
||||
st::settingsDividerLabelPadding));
|
||||
st::defaultBoxDividerLabelPadding));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1070,7 +1064,7 @@ void Controller::fillManageSection() {
|
|||
&& (channel->linkedChat()
|
||||
|| (channel->isBroadcast() && channel->canEditInformation()));
|
||||
|
||||
AddSkip(_controls.buttonsLayout, 0);
|
||||
::AddSkip(_controls.buttonsLayout, 0);
|
||||
|
||||
if (canEditType) {
|
||||
fillPrivacyTypeButton();
|
||||
|
@ -1099,11 +1093,10 @@ void Controller::fillManageSection() {
|
|||
//|| canEditInviteLinks
|
||||
|| canViewOrEditLinkedChat
|
||||
|| canEditType) {
|
||||
AddSkip(_controls.buttonsLayout);
|
||||
::AddSkip(_controls.buttonsLayout);
|
||||
}
|
||||
|
||||
if (canEditReactions()) {
|
||||
const auto session = &_peer->session();
|
||||
auto allowedReactions = Info::Profile::MigratedOrMeValue(
|
||||
_peer
|
||||
) | rpl::map([=](not_null<PeerData*> peer) {
|
||||
|
@ -1114,36 +1107,21 @@ void Controller::fillManageSection() {
|
|||
return Data::PeerAllowedReactions(peer);
|
||||
});
|
||||
}) | rpl::flatten_latest();
|
||||
auto label = rpl::combine(
|
||||
std::move(allowedReactions),
|
||||
Info::Profile::FullReactionsCountValue(session)
|
||||
) | rpl::map([=](const Data::AllowedReactions &allowed, int total) {
|
||||
auto label = std::move(
|
||||
allowedReactions
|
||||
) | rpl::map([=](const Data::AllowedReactions &allowed) {
|
||||
const auto some = int(allowed.some.size());
|
||||
return (allowed.type != Data::AllowedReactionsType::Some)
|
||||
? tr::lng_manage_peer_reactions_on(tr::now)
|
||||
: some
|
||||
? (QString::number(some)
|
||||
+ " / "
|
||||
+ QString::number(std::max(some, total)))
|
||||
? QString::number(some)
|
||||
: tr::lng_manage_peer_reactions_off(tr::now);
|
||||
});
|
||||
const auto done = [=](const Data::AllowedReactions &chosen) {
|
||||
SaveAllowedReactions(_peer, chosen);
|
||||
};
|
||||
AddButtonWithCount(
|
||||
_controls.buttonsLayout,
|
||||
tr::lng_manage_peer_reactions(),
|
||||
std::move(label),
|
||||
[=] {
|
||||
_navigation->parentController()->show(Box(
|
||||
EditAllowedReactionsBox,
|
||||
_navigation,
|
||||
!_peer->isBroadcast(),
|
||||
session->data().reactions().list(
|
||||
Data::Reactions::Type::Active),
|
||||
Data::PeerAllowedReactions(_peer),
|
||||
done));
|
||||
},
|
||||
[=] { editReactions(); },
|
||||
{ &st::menuIconGroupReactions });
|
||||
}
|
||||
if (canEditPermissions) {
|
||||
|
@ -1269,7 +1247,7 @@ void Controller::fillManageSection() {
|
|||
}
|
||||
|
||||
if (canEditStickers || canDeleteChannel) {
|
||||
AddSkip(_controls.buttonsLayout);
|
||||
::AddSkip(_controls.buttonsLayout);
|
||||
}
|
||||
|
||||
if (canEditStickers) {
|
||||
|
@ -1287,10 +1265,67 @@ void Controller::fillManageSection() {
|
|||
}
|
||||
|
||||
if (canEditStickers || canDeleteChannel) {
|
||||
AddSkip(_controls.buttonsLayout);
|
||||
::AddSkip(_controls.buttonsLayout);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::editReactions() {
|
||||
const auto done = [=](const Data::AllowedReactions &chosen) {
|
||||
SaveAllowedReactions(_peer, chosen);
|
||||
};
|
||||
if (!_peer->isBroadcast()) {
|
||||
_navigation->uiShow()->show(Box(
|
||||
EditAllowedReactionsBox,
|
||||
EditAllowedReactionsArgs{
|
||||
.navigation = _navigation,
|
||||
.isGroup = true,
|
||||
.list = _navigation->session().data().reactions().list(
|
||||
Data::Reactions::Type::Active),
|
||||
.allowed = Data::PeerAllowedReactions(_peer),
|
||||
.save = done,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
if (_controls.levelRequested) {
|
||||
return;
|
||||
}
|
||||
_controls.levelRequested = true;
|
||||
_api.request(MTPpremium_GetBoostsStatus(
|
||||
_peer->input
|
||||
)).done([=](const MTPpremium_BoostsStatus &result) {
|
||||
_controls.levelRequested = false;
|
||||
const auto link = qs(result.data().vboost_url());
|
||||
const auto weak = base::make_weak(_navigation->parentController());
|
||||
auto counters = ParseBoostCounters(result);
|
||||
counters.mine = 0; // Don't show current level as just-reached.
|
||||
const auto askForBoosts = [=](int required) {
|
||||
if (const auto strong = weak.get()) {
|
||||
const auto openStatistics = [=, peer = _peer] {
|
||||
strong->showSection(Info::Boosts::Make(peer));
|
||||
};
|
||||
strong->show(Box(Ui::AskBoostBox, Ui::AskBoostBoxData{
|
||||
.link = link,
|
||||
.boost = counters,
|
||||
.reason = { Ui::AskBoostCustomReactions{ required } },
|
||||
}, openStatistics, nullptr));
|
||||
}
|
||||
};
|
||||
_navigation->uiShow()->show(Box(
|
||||
EditAllowedReactionsBox,
|
||||
EditAllowedReactionsArgs{
|
||||
.navigation = _navigation,
|
||||
.allowedCustomReactions = counters.level,
|
||||
.customReactionsHardLimit = Data::PremiumLimits(
|
||||
&_peer->session()).maxBoostLevel(),
|
||||
.list = _navigation->session().data().reactions().list(
|
||||
Data::Reactions::Type::Active),
|
||||
.allowed = Data::PeerAllowedReactions(_peer),
|
||||
.askForBoosts = askForBoosts,
|
||||
.save = done,
|
||||
}));
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Controller::fillPendingRequestsButton() {
|
||||
auto pendingRequestsCount = Info::Profile::MigratedOrMeValue(
|
||||
_peer
|
||||
|
|
|
@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/boxes/edit_invite_link.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "boxes/share_box.h"
|
||||
#include "history/view/history_view_group_call_bar.h" // GenerateUserpics...
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
|
@ -39,14 +40,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "qr/qr_generate.h"
|
||||
#include "intro/intro_qr.h" // TelegramLogoImage
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_layers.h" // st::boxDividerLabel.
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
@ -434,7 +433,7 @@ void Controller::addHeaderBlock(not_null<Ui::VerticalLayout*> container) {
|
|||
AddDeleteLinkButton(container, deleteLink);
|
||||
}
|
||||
|
||||
AddSkip(container, st::inviteLinkJoinedRowPadding.bottom() * 2);
|
||||
Ui::AddSkip(container, st::inviteLinkJoinedRowPadding.bottom() * 2);
|
||||
|
||||
auto grayLabelText = dataValue(
|
||||
) | rpl::map([=](const LinkData &data) {
|
||||
|
@ -457,7 +456,7 @@ void Controller::addHeaderBlock(not_null<Ui::VerticalLayout*> container) {
|
|||
container,
|
||||
tr::lng_group_invite_expired_about(),
|
||||
st::boxAttentionDividerLabel),
|
||||
st::settingsDividerLabelPadding)));
|
||||
st::defaultBoxDividerLabelPadding)));
|
||||
const auto grayLabelWrap = container->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::DividerLabel>>(
|
||||
container,
|
||||
|
@ -467,12 +466,12 @@ void Controller::addHeaderBlock(not_null<Ui::VerticalLayout*> container) {
|
|||
container,
|
||||
std::move(grayLabelText),
|
||||
st::boxDividerLabel),
|
||||
st::settingsDividerLabelPadding)));
|
||||
st::defaultBoxDividerLabelPadding)));
|
||||
const auto justDividerWrap = container->add(
|
||||
object_ptr<Ui::SlideWrap<>>(
|
||||
container,
|
||||
object_ptr<Ui::BoxContentDivider>(container)));
|
||||
AddSkip(container);
|
||||
Ui::AddSkip(container);
|
||||
|
||||
dataValue(
|
||||
) | rpl::start_with_next([=](const LinkData &data) {
|
||||
|
@ -509,15 +508,15 @@ not_null<Ui::SlideWrap<>*> Controller::addRequestedListBlock(
|
|||
const auto wrap = result->entity();
|
||||
// Make this container occupy full width.
|
||||
wrap->add(object_ptr<Ui::RpWidget>(wrap));
|
||||
AddDivider(wrap);
|
||||
AddSkip(wrap);
|
||||
Ui::AddDivider(wrap);
|
||||
Ui::AddSkip(wrap);
|
||||
auto requestedCount = dataValue(
|
||||
) | rpl::filter([](const LinkData &data) {
|
||||
return data.requested > 0;
|
||||
}) | rpl::map([=](const LinkData &data) {
|
||||
return float64(data.requested);
|
||||
});
|
||||
AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
wrap,
|
||||
tr::lng_group_invite_requested_full(
|
||||
lt_count_decimal,
|
||||
|
@ -588,14 +587,14 @@ void Controller::setupAboveJoinedWidget() {
|
|||
if (revoked || !current.permanent) {
|
||||
addHeaderBlock(container);
|
||||
}
|
||||
AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
container,
|
||||
tr::lng_group_invite_created_by());
|
||||
AddSinglePeerRow(
|
||||
container,
|
||||
current.admin,
|
||||
rpl::single(langDateTime(base::unixtime::parse(current.date))));
|
||||
AddSkip(container, st::membersMarginBottom);
|
||||
Ui::AddSkip(container, st::membersMarginBottom);
|
||||
|
||||
auto requestedWrap = addRequestedListBlock(container);
|
||||
|
||||
|
@ -609,8 +608,8 @@ void Controller::setupAboveJoinedWidget() {
|
|||
// Make this container occupy full width.
|
||||
listHeader->add(object_ptr<Ui::RpWidget>(listHeader));
|
||||
|
||||
AddDivider(listHeader);
|
||||
AddSkip(listHeader);
|
||||
Ui::AddDivider(listHeader);
|
||||
Ui::AddSkip(listHeader);
|
||||
|
||||
auto listHeaderText = dataValue(
|
||||
) | rpl::map([=](const LinkData &data) {
|
||||
|
@ -665,7 +664,7 @@ void Controller::setupAboveJoinedWidget() {
|
|||
const auto remaining = Ui::CreateChild<Ui::FlatLabel>(
|
||||
listHeader,
|
||||
std::move(remainingText),
|
||||
st::settingsSubsectionTitleRight);
|
||||
st::inviteLinkTitleRight);
|
||||
dataValue(
|
||||
) | rpl::start_with_next([=](const LinkData &data) {
|
||||
remaining->setTextColorOverride(
|
||||
|
|
|
@ -19,17 +19,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/edit_peer_invite_link.h"
|
||||
#include "settings/settings_common.h" // AddDivider.
|
||||
#include "apiwrap.h"
|
||||
#include "base/weak_ptr.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_layers.h" // st::boxDividerLabel
|
||||
#include "styles/style_settings.h" // st::settingsDividerLabelPadding
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
namespace {
|
||||
|
@ -875,8 +874,6 @@ void ManageInviteLinksBox(
|
|||
not_null<UserData*> admin,
|
||||
int count,
|
||||
int revokedCount) {
|
||||
using namespace Settings;
|
||||
|
||||
const auto show = Main::MakeSessionShow(
|
||||
box->uiShow(),
|
||||
&peer->session());
|
||||
|
@ -901,14 +898,14 @@ void ManageInviteLinksBox(
|
|||
std::move(status));
|
||||
}
|
||||
|
||||
AddSubsectionTitle(container, tr::lng_create_permanent_link_title());
|
||||
Ui::AddSubsectionTitle(container, tr::lng_create_permanent_link_title());
|
||||
AddPermanentLinkBlock(
|
||||
show,
|
||||
container,
|
||||
peer,
|
||||
admin,
|
||||
permanentFromList->events());
|
||||
AddDivider(container);
|
||||
Ui::AddDivider(container);
|
||||
|
||||
auto otherHeader = (Ui::SlideWrap<>*)nullptr;
|
||||
if (admin->isSelf()) {
|
||||
|
@ -923,7 +920,7 @@ void ManageInviteLinksBox(
|
|||
object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
tr::lng_group_invite_other_list(),
|
||||
st::settingsSubsectionTitle),
|
||||
st::defaultSubsectionTitle),
|
||||
st::inviteLinkRevokedTitlePadding));
|
||||
}
|
||||
|
||||
|
@ -949,7 +946,7 @@ void ManageInviteLinksBox(
|
|||
container,
|
||||
tr::lng_group_invite_add_about(),
|
||||
st::boxDividerLabel),
|
||||
st::settingsDividerLabelPadding)),
|
||||
st::defaultBoxDividerLabelPadding)),
|
||||
style::margins(0, st::inviteLinkCreateSkip, 0, 0));
|
||||
|
||||
const auto adminsDivider = container->add(object_ptr<Ui::SlideWrap<>>(
|
||||
|
@ -960,7 +957,7 @@ void ManageInviteLinksBox(
|
|||
object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
tr::lng_group_invite_other_title(),
|
||||
st::settingsSubsectionTitle),
|
||||
st::defaultSubsectionTitle),
|
||||
st::inviteLinkRevokedTitlePadding));
|
||||
const auto admins = AddAdminsList(show, container, peer, admin);
|
||||
|
||||
|
@ -972,7 +969,7 @@ void ManageInviteLinksBox(
|
|||
object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
tr::lng_group_invite_revoked_title(),
|
||||
st::settingsSubsectionTitle),
|
||||
st::defaultSubsectionTitle),
|
||||
st::inviteLinkRevokedTitlePadding));
|
||||
const auto revoked = AddLinksList(
|
||||
show,
|
||||
|
|
|
@ -611,7 +611,7 @@ template <typename Flags>
|
|||
|
||||
return checkView;
|
||||
} else {
|
||||
const auto button = Settings::AddButton(
|
||||
const auto button = Settings::AddButtonWithIcon(
|
||||
verticalLayout,
|
||||
rpl::single(entry.label),
|
||||
st,
|
||||
|
|
|
@ -7,48 +7,599 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "boxes/peers/edit_peer_reactions.h"
|
||||
|
||||
#include "boxes/reactions_settings_box.h" // AddReactionAnimatedIcon
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "chat_helpers/tabbed_panel.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/view/reactions/history_view_reactions_selector.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/boxes/boost_box.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "window/window_session_controller_link_info.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
#include <QtWidgets/QTextEdit>
|
||||
#include <QtGui/QTextBlock>
|
||||
#include <QtGui/QTextDocumentFragment>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kDisabledEmojiOpacity = 0.4;
|
||||
|
||||
struct UniqueCustomEmojiContext {
|
||||
std::vector<DocumentId> ids;
|
||||
Fn<bool(DocumentId)> applyHardLimit;
|
||||
int hardLimit = 0;
|
||||
int hardLimitChecked = 0;
|
||||
bool hardLimitHit = false;
|
||||
};
|
||||
|
||||
class MaybeDisabledEmoji final : public Ui::Text::CustomEmoji {
|
||||
public:
|
||||
MaybeDisabledEmoji(
|
||||
std::unique_ptr<CustomEmoji> wrapped,
|
||||
Fn<bool()> enabled);
|
||||
|
||||
int width() override;
|
||||
QString entityData() override;
|
||||
void paint(QPainter &p, const Context &context) override;
|
||||
void unload() override;
|
||||
bool ready() override;
|
||||
bool readyInDefaultState() override;
|
||||
|
||||
private:
|
||||
const std::unique_ptr<Ui::Text::CustomEmoji> _wrapped;
|
||||
const Fn<bool()> _enabled;
|
||||
|
||||
};
|
||||
|
||||
MaybeDisabledEmoji::MaybeDisabledEmoji(
|
||||
std::unique_ptr<CustomEmoji> wrapped,
|
||||
Fn<bool()> enabled)
|
||||
: _wrapped(std::move(wrapped))
|
||||
, _enabled(std::move(enabled)) {
|
||||
}
|
||||
|
||||
int MaybeDisabledEmoji::width() {
|
||||
return _wrapped->width();
|
||||
}
|
||||
|
||||
QString MaybeDisabledEmoji::entityData() {
|
||||
return _wrapped->entityData();
|
||||
}
|
||||
|
||||
void MaybeDisabledEmoji::paint(QPainter &p, const Context &context) {
|
||||
const auto disabled = !_enabled();
|
||||
const auto was = disabled ? p.opacity() : 1.;
|
||||
if (disabled) {
|
||||
p.setOpacity(kDisabledEmojiOpacity);
|
||||
}
|
||||
_wrapped->paint(p, context);
|
||||
if (disabled) {
|
||||
p.setOpacity(was);
|
||||
}
|
||||
}
|
||||
|
||||
void MaybeDisabledEmoji::unload() {
|
||||
_wrapped->unload();
|
||||
}
|
||||
|
||||
bool MaybeDisabledEmoji::ready() {
|
||||
return _wrapped->ready();
|
||||
}
|
||||
|
||||
bool MaybeDisabledEmoji::readyInDefaultState() {
|
||||
return _wrapped->readyInDefaultState();
|
||||
}
|
||||
|
||||
[[nodiscard]] QString AllowOnlyCustomEmojiProcessor(QStringView mimeTag) {
|
||||
auto all = TextUtilities::SplitTags(mimeTag);
|
||||
for (auto i = all.begin(); i != all.end();) {
|
||||
if (Ui::InputField::IsCustomEmojiLink(*i)) {
|
||||
++i;
|
||||
} else {
|
||||
i = all.erase(i);
|
||||
}
|
||||
}
|
||||
return TextUtilities::JoinTag(all);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool AllowOnlyCustomEmojiMimeDataHook(
|
||||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
const auto textMime = TextUtilities::TagsTextMimeType();
|
||||
const auto tagsMime = TextUtilities::TagsMimeType();
|
||||
if (!data->hasFormat(textMime) || !data->hasFormat(tagsMime)) {
|
||||
return false;
|
||||
}
|
||||
auto text = QString::fromUtf8(data->data(textMime));
|
||||
auto tags = TextUtilities::DeserializeTags(
|
||||
data->data(tagsMime),
|
||||
text.size());
|
||||
auto checkedTill = 0;
|
||||
ranges::sort(tags, ranges::less(), &TextWithTags::Tag::offset);
|
||||
for (const auto &tag : tags) {
|
||||
if (tag.offset != checkedTill
|
||||
|| AllowOnlyCustomEmojiProcessor(tag.id) != tag.id) {
|
||||
return false;
|
||||
}
|
||||
checkedTill += tag.length;
|
||||
}
|
||||
return true;
|
||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||
return false;
|
||||
}
|
||||
Unexpected("Action in MimeData hook.");
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<Data::ReactionId> DefaultSelected() {
|
||||
const auto like = QString::fromUtf8("\xf0\x9f\x91\x8d");
|
||||
const auto dislike = QString::fromUtf8("\xf0\x9f\x91\x8e");
|
||||
return { Data::ReactionId{ like }, Data::ReactionId{ dislike } };
|
||||
}
|
||||
|
||||
[[nodiscard]] bool RemoveNonCustomEmojiFragment(
|
||||
not_null<QTextDocument*> document,
|
||||
UniqueCustomEmojiContext &context) {
|
||||
context.ids.clear();
|
||||
context.hardLimitChecked = 0;
|
||||
auto removeFrom = 0;
|
||||
auto removeTill = 0;
|
||||
auto block = document->begin();
|
||||
for (auto j = block.begin(); !j.atEnd(); ++j) {
|
||||
const auto fragment = j.fragment();
|
||||
Assert(fragment.isValid());
|
||||
|
||||
removeTill = removeFrom = fragment.position();
|
||||
const auto format = fragment.charFormat();
|
||||
if (format.objectType() != Ui::InputField::kCustomEmojiFormat) {
|
||||
removeTill += fragment.length();
|
||||
break;
|
||||
}
|
||||
const auto id = format.property(Ui::InputField::kCustomEmojiId);
|
||||
const auto documentId = id.toULongLong();
|
||||
const auto applyHardLimit = context.applyHardLimit(documentId);
|
||||
if (ranges::contains(context.ids, documentId)) {
|
||||
removeTill += fragment.length();
|
||||
break;
|
||||
} else if (applyHardLimit
|
||||
&& context.hardLimitChecked >= context.hardLimit) {
|
||||
context.hardLimitHit = true;
|
||||
removeTill += fragment.length();
|
||||
break;
|
||||
}
|
||||
context.ids.push_back(documentId);
|
||||
if (applyHardLimit) {
|
||||
++context.hardLimitChecked;
|
||||
}
|
||||
}
|
||||
while (removeTill == removeFrom) {
|
||||
block = block.next();
|
||||
if (block == document->end()) {
|
||||
return false;
|
||||
}
|
||||
removeTill = block.position();
|
||||
}
|
||||
Ui::PrepareFormattingOptimization(document);
|
||||
auto cursor = QTextCursor(document);
|
||||
cursor.setPosition(removeFrom);
|
||||
cursor.setPosition(removeTill, QTextCursor::KeepAnchor);
|
||||
cursor.removeSelectedText();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoveNonCustomEmoji(
|
||||
not_null<QTextDocument*> document,
|
||||
UniqueCustomEmojiContext &context) {
|
||||
if (!RemoveNonCustomEmojiFragment(document, context)) {
|
||||
return false;
|
||||
}
|
||||
while (RemoveNonCustomEmojiFragment(document, context)) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetupOnlyCustomEmojiField(
|
||||
not_null<Ui::InputField*> field,
|
||||
Fn<void(std::vector<DocumentId>, bool)> callback,
|
||||
Fn<bool(DocumentId)> applyHardLimit,
|
||||
int customHardLimit) {
|
||||
field->setTagMimeProcessor(AllowOnlyCustomEmojiProcessor);
|
||||
field->setMimeDataHook(AllowOnlyCustomEmojiMimeDataHook);
|
||||
|
||||
struct State {
|
||||
bool processing = false;
|
||||
bool pending = false;
|
||||
};
|
||||
const auto state = field->lifetime().make_state<State>();
|
||||
|
||||
field->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
state->pending = true;
|
||||
if (state->processing) {
|
||||
return;
|
||||
}
|
||||
auto context = UniqueCustomEmojiContext{
|
||||
.applyHardLimit = applyHardLimit,
|
||||
.hardLimit = customHardLimit,
|
||||
};
|
||||
auto changed = false;
|
||||
state->processing = true;
|
||||
while (state->pending) {
|
||||
state->pending = false;
|
||||
const auto document = field->rawTextEdit()->document();
|
||||
const auto pageSize = document->pageSize();
|
||||
QTextCursor(document).joinPreviousEditBlock();
|
||||
if (RemoveNonCustomEmoji(document, context)) {
|
||||
changed = true;
|
||||
}
|
||||
state->processing = false;
|
||||
QTextCursor(document).endEditBlock();
|
||||
if (document->pageSize() != pageSize) {
|
||||
document->setPageSize(pageSize);
|
||||
}
|
||||
}
|
||||
callback(context.ids, context.hardLimitHit);
|
||||
if (changed) {
|
||||
field->forceProcessContentsChanges();
|
||||
}
|
||||
}, field->lifetime());
|
||||
}
|
||||
|
||||
[[nodiscard]] TextWithTags ComposeEmojiList(
|
||||
not_null<Data::Reactions*> reactions,
|
||||
const std::vector<Data::ReactionId> &list) {
|
||||
auto result = TextWithTags();
|
||||
const auto size = [&] {
|
||||
return int(result.text.size());
|
||||
};
|
||||
auto added = base::flat_set<Data::ReactionId>();
|
||||
const auto &all = reactions->list(Data::Reactions::Type::All);
|
||||
const auto add = [&](Data::ReactionId id) {
|
||||
if (!added.emplace(id).second) {
|
||||
return;
|
||||
}
|
||||
auto unifiedId = id.custom();
|
||||
const auto offset = size();
|
||||
if (unifiedId) {
|
||||
result.text.append('@');
|
||||
} else {
|
||||
result.text.append(id.emoji());
|
||||
const auto i = ranges::find(all, id, &Data::Reaction::id);
|
||||
if (i == end(all)) {
|
||||
return;
|
||||
}
|
||||
unifiedId = i->selectAnimation->id;
|
||||
}
|
||||
const auto data = Data::SerializeCustomEmojiId(unifiedId);
|
||||
const auto tag = Ui::InputField::CustomEmojiLink(data);
|
||||
result.tags.append({ offset, size() - offset, tag });
|
||||
};
|
||||
for (const auto &id : list) {
|
||||
add(id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
enum class ReactionsSelectorState {
|
||||
Active,
|
||||
Disabled,
|
||||
Hidden,
|
||||
};
|
||||
|
||||
struct ReactionsSelectorArgs {
|
||||
not_null<QWidget*> outer;
|
||||
not_null<Window::SessionController*> controller;
|
||||
rpl::producer<QString> title;
|
||||
std::vector<Data::Reaction> list;
|
||||
std::vector<Data::ReactionId> selected;
|
||||
Fn<void(std::vector<Data::ReactionId>, bool)> callback;
|
||||
rpl::producer<ReactionsSelectorState> stateValue;
|
||||
int customAllowed = 0;
|
||||
int customHardLimit = 0;
|
||||
bool all = false;
|
||||
};
|
||||
|
||||
object_ptr<Ui::RpWidget> AddReactionsSelector(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
ReactionsSelectorArgs &&args) {
|
||||
using namespace ChatHelpers;
|
||||
using HistoryView::Reactions::UnifiedFactoryOwner;
|
||||
|
||||
auto result = object_ptr<Ui::InputField>(
|
||||
parent,
|
||||
st::manageGroupReactionsField,
|
||||
Ui::InputField::Mode::MultiLine,
|
||||
std::move(args.title));
|
||||
const auto raw = result.data();
|
||||
const auto session = &args.controller->session();
|
||||
const auto owner = &session->data();
|
||||
const auto reactions = &owner->reactions();
|
||||
const auto customAllowed = args.customAllowed;
|
||||
|
||||
struct State {
|
||||
std::unique_ptr<Ui::RpWidget> overlay;
|
||||
std::unique_ptr<UnifiedFactoryOwner> unifiedFactoryOwner;
|
||||
UnifiedFactoryOwner::RecentFactory factory;
|
||||
base::flat_set<DocumentId> allowed;
|
||||
rpl::lifetime focusLifetime;
|
||||
};
|
||||
const auto state = raw->lifetime().make_state<State>();
|
||||
state->unifiedFactoryOwner = std::make_unique<UnifiedFactoryOwner>(
|
||||
session,
|
||||
reactions->list(Data::Reactions::Type::Active));
|
||||
state->factory = state->unifiedFactoryOwner->factory();
|
||||
|
||||
const auto customEmojiPaused = [controller = args.controller] {
|
||||
return controller->isGifPausedAtLeastFor(PauseReason::Layer);
|
||||
};
|
||||
raw->setCustomEmojiFactory([=](QStringView data, Fn<void()> update)
|
||||
-> std::unique_ptr<Ui::Text::CustomEmoji> {
|
||||
const auto id = Data::ParseCustomEmojiData(data);
|
||||
auto result = owner->customEmojiManager().create(
|
||||
data,
|
||||
std::move(update));
|
||||
if (state->unifiedFactoryOwner->lookupReactionId(id).custom()) {
|
||||
return std::make_unique<MaybeDisabledEmoji>(
|
||||
std::move(result),
|
||||
[=] { return state->allowed.contains(id); });
|
||||
}
|
||||
using namespace Ui::Text;
|
||||
return std::make_unique<FirstFrameEmoji>(std::move(result));
|
||||
}, std::move(customEmojiPaused));
|
||||
|
||||
const auto callback = args.callback;
|
||||
const auto isCustom = [=](DocumentId id) {
|
||||
return state->unifiedFactoryOwner->lookupReactionId(id).custom();
|
||||
};
|
||||
SetupOnlyCustomEmojiField(raw, [=](
|
||||
std::vector<DocumentId> ids,
|
||||
bool hardLimitHit) {
|
||||
auto allowed = base::flat_set<DocumentId>();
|
||||
auto reactions = std::vector<Data::ReactionId>();
|
||||
reactions.reserve(ids.size());
|
||||
allowed.reserve(std::min(customAllowed, int(ids.size())));
|
||||
const auto owner = state->unifiedFactoryOwner.get();
|
||||
for (const auto id : ids) {
|
||||
const auto reactionId = owner->lookupReactionId(id);
|
||||
if (reactionId.custom() && allowed.size() < customAllowed) {
|
||||
allowed.emplace(id);
|
||||
}
|
||||
reactions.push_back(reactionId);
|
||||
}
|
||||
if (state->allowed != allowed) {
|
||||
state->allowed = std::move(allowed);
|
||||
raw->rawTextEdit()->update();
|
||||
}
|
||||
callback(std::move(reactions), hardLimitHit);
|
||||
}, isCustom, args.customHardLimit);
|
||||
raw->setTextWithTags(ComposeEmojiList(reactions, args.selected));
|
||||
|
||||
using SelectorState = ReactionsSelectorState;
|
||||
std::move(
|
||||
args.stateValue
|
||||
) | rpl::start_with_next([=](SelectorState value) {
|
||||
switch (value) {
|
||||
case SelectorState::Active:
|
||||
state->overlay = nullptr;
|
||||
state->focusLifetime.destroy();
|
||||
if (raw->empty()) {
|
||||
raw->setTextWithTags(
|
||||
ComposeEmojiList(reactions, DefaultSelected()));
|
||||
}
|
||||
raw->setDisabled(false);
|
||||
raw->setFocusFast();
|
||||
break;
|
||||
case SelectorState::Disabled:
|
||||
state->overlay = std::make_unique<Ui::RpWidget>(parent);
|
||||
state->overlay->show();
|
||||
raw->geometryValue() | rpl::start_with_next([=](QRect rect) {
|
||||
state->overlay->setGeometry(rect);
|
||||
}, state->overlay->lifetime());
|
||||
state->overlay->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
auto color = st::boxBg->c;
|
||||
color.setAlphaF(0.5);
|
||||
QPainter(state->overlay.get()).fillRect(
|
||||
clip,
|
||||
color);
|
||||
}, state->overlay->lifetime());
|
||||
[[fallthrough]];
|
||||
case SelectorState::Hidden:
|
||||
if (Ui::InFocusChain(raw)) {
|
||||
raw->parentWidget()->setFocus();
|
||||
}
|
||||
raw->setDisabled(true);
|
||||
raw->focusedChanges(
|
||||
) | rpl::start_with_next([=](bool focused) {
|
||||
if (focused) {
|
||||
raw->parentWidget()->setFocus();
|
||||
}
|
||||
}, state->focusLifetime);
|
||||
break;
|
||||
}
|
||||
}, raw->lifetime());
|
||||
|
||||
const auto toggle = Ui::CreateChild<Ui::IconButton>(
|
||||
parent.get(),
|
||||
st::manageGroupReactions);
|
||||
|
||||
const auto panel = Ui::CreateChild<TabbedPanel>(
|
||||
args.outer.get(),
|
||||
args.controller,
|
||||
object_ptr<TabbedSelector>(
|
||||
nullptr,
|
||||
args.controller->uiShow(),
|
||||
Window::GifPauseReason::Layer,
|
||||
(args.all
|
||||
? TabbedSelector::Mode::FullReactions
|
||||
: TabbedSelector::Mode::RecentReactions)));
|
||||
panel->selector()->provideRecentEmoji(
|
||||
state->unifiedFactoryOwner->unifiedIdsList());
|
||||
panel->setDesiredHeightValues(
|
||||
1.,
|
||||
st::emojiPanMinHeight / 2,
|
||||
st::emojiPanMinHeight);
|
||||
panel->hide();
|
||||
panel->selector()->customEmojiChosen(
|
||||
) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
|
||||
Data::InsertCustomEmoji(raw, data.document);
|
||||
}, panel->lifetime());
|
||||
|
||||
const auto updateEmojiPanelGeometry = [=] {
|
||||
const auto parent = panel->parentWidget();
|
||||
const auto global = toggle->mapToGlobal({ 0, 0 });
|
||||
const auto local = parent->mapFromGlobal(global);
|
||||
panel->moveBottomRight(
|
||||
local.y(),
|
||||
local.x() + toggle->width() * 3);
|
||||
};
|
||||
const auto scheduleUpdateEmojiPanelGeometry = [=] {
|
||||
// updateEmojiPanelGeometry uses not only container geometry, but
|
||||
// also container children geometries that will be updated later.
|
||||
crl::on_main(raw, updateEmojiPanelGeometry);
|
||||
};
|
||||
const auto filterCallback = [=](not_null<QEvent*> event) {
|
||||
const auto type = event->type();
|
||||
if (type == QEvent::Move || type == QEvent::Resize) {
|
||||
scheduleUpdateEmojiPanelGeometry();
|
||||
}
|
||||
return base::EventFilterResult::Continue;
|
||||
};
|
||||
for (auto widget = (QWidget*)raw
|
||||
; widget && widget != args.outer
|
||||
; widget = widget->parentWidget()) {
|
||||
base::install_event_filter(raw, widget, filterCallback);
|
||||
}
|
||||
base::install_event_filter(raw, args.outer, filterCallback);
|
||||
scheduleUpdateEmojiPanelGeometry();
|
||||
|
||||
toggle->installEventFilter(panel);
|
||||
toggle->addClickHandler([=] {
|
||||
panel->toggleAnimated();
|
||||
});
|
||||
|
||||
raw->geometryValue() | rpl::start_with_next([=](QRect geometry) {
|
||||
toggle->move(
|
||||
geometry.x() + geometry.width() - toggle->width(),
|
||||
geometry.y() + geometry.height() - toggle->height());
|
||||
updateEmojiPanelGeometry();
|
||||
}, toggle->lifetime());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void AddReactionsText(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
int allowedCustomReactions,
|
||||
rpl::producer<int> customCountValue,
|
||||
Fn<void(int required)> askForBoosts) {
|
||||
auto ownedInner = object_ptr<Ui::VerticalLayout>(container);
|
||||
const auto inner = ownedInner.data();
|
||||
const auto count = inner->lifetime().make_state<rpl::variable<int>>(
|
||||
std::move(customCountValue));
|
||||
|
||||
container->add(
|
||||
object_ptr<Ui::DividerLabel>(
|
||||
container,
|
||||
std::move(ownedInner),
|
||||
st::defaultBoxDividerLabelPadding),
|
||||
QMargins(0, st::manageGroupReactionsTextSkip, 0, 0));
|
||||
const auto label = inner->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
inner,
|
||||
tr::lng_manage_peer_reactions_own(
|
||||
lt_link,
|
||||
tr::lng_manage_peer_reactions_own_link(
|
||||
) | Ui::Text::ToLink(),
|
||||
Ui::Text::WithEntities),
|
||||
st::boxDividerLabel));
|
||||
const auto weak = base::make_weak(navigation);
|
||||
label->setClickHandlerFilter([=](const auto &...) {
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->showPeerByLink(Window::PeerByLinkInfo{
|
||||
.usernameOrId = u"stickers"_q,
|
||||
.resolveType = Window::ResolveType::Mention,
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
auto countString = count->value() | rpl::map([](int count) {
|
||||
return TextWithEntities{ QString::number(count) };
|
||||
});
|
||||
auto needs = rpl::combine(
|
||||
tr::lng_manage_peer_reactions_level(
|
||||
lt_count,
|
||||
count->value() | tr::to_count(),
|
||||
lt_same_count,
|
||||
std::move(countString),
|
||||
Ui::Text::RichLangValue),
|
||||
tr::lng_manage_peer_reactions_boost(
|
||||
lt_link,
|
||||
tr::lng_manage_peer_reactions_boost_link() | Ui::Text::ToLink(),
|
||||
Ui::Text::RichLangValue)
|
||||
) | rpl::map([](TextWithEntities &&a, TextWithEntities &&b) {
|
||||
a.append(' ').append(std::move(b));
|
||||
return std::move(a);
|
||||
});
|
||||
const auto wrap = inner->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
|
||||
inner,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
inner,
|
||||
std::move(needs),
|
||||
st::boxDividerLabel),
|
||||
QMargins{ 0, st::normalFont->height, 0, 0 }));
|
||||
wrap->toggleOn(count->value() | rpl::map(
|
||||
rpl::mappers::_1 > allowedCustomReactions
|
||||
));
|
||||
wrap->finishAnimating();
|
||||
|
||||
wrap->entity()->setClickHandlerFilter([=](const auto &...) {
|
||||
askForBoosts(count->current());
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void EditAllowedReactionsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
bool isGroup,
|
||||
const std::vector<Data::Reaction> &list,
|
||||
const Data::AllowedReactions &allowed,
|
||||
Fn<void(const Data::AllowedReactions &)> callback) {
|
||||
EditAllowedReactionsArgs &&args) {
|
||||
using namespace Data;
|
||||
using namespace rpl::mappers;
|
||||
|
||||
const auto iconHeight = st::editPeerReactionsPreview;
|
||||
box->setTitle(tr::lng_manage_peer_reactions());
|
||||
box->setWidth(st::boxWideWidth);
|
||||
|
||||
enum class Option {
|
||||
All,
|
||||
Some,
|
||||
None,
|
||||
};
|
||||
using SelectorState = ReactionsSelectorState;
|
||||
struct State {
|
||||
base::flat_map<ReactionId, not_null<Ui::SettingsButton*>> toggles;
|
||||
rpl::variable<Option> option; // For groups.
|
||||
rpl::variable<bool> anyToggled; // For channels.
|
||||
rpl::event_stream<bool> forceToggleAll; // For channels.
|
||||
rpl::variable<SelectorState> selectorState;
|
||||
std::vector<Data::ReactionId> selected;
|
||||
rpl::variable<int> customCount;
|
||||
};
|
||||
const auto allowed = args.allowed;
|
||||
const auto optionInitial = (allowed.type != AllowedReactionsType::Some)
|
||||
? Option::All
|
||||
: allowed.some.empty()
|
||||
|
@ -56,57 +607,24 @@ void EditAllowedReactionsBox(
|
|||
: Option::Some;
|
||||
const auto state = box->lifetime().make_state<State>(State{
|
||||
.option = optionInitial,
|
||||
.anyToggled = (optionInitial != Option::None),
|
||||
});
|
||||
|
||||
const auto collect = [=] {
|
||||
auto result = AllowedReactions();
|
||||
if (!isGroup || state->option.current() == Option::Some) {
|
||||
result.some.reserve(state->toggles.size());
|
||||
for (const auto &[id, button] : state->toggles) {
|
||||
if (button->toggled()) {
|
||||
result.some.push_back(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.type = isGroup
|
||||
? (state->option.current() != Option::All
|
||||
? AllowedReactionsType::Some
|
||||
: AllowedReactionsType::All)
|
||||
: (result.some.size() == state->toggles.size())
|
||||
? AllowedReactionsType::Default
|
||||
: AllowedReactionsType::Some;
|
||||
return result;
|
||||
};
|
||||
|
||||
const auto container = box->verticalLayout();
|
||||
|
||||
const auto enabled = isGroup ? nullptr : Settings::AddButton(
|
||||
container,
|
||||
tr::lng_manage_peer_reactions_enable(),
|
||||
st::manageGroupButton.button
|
||||
).get();
|
||||
if (enabled && !list.empty()) {
|
||||
AddReactionAnimatedIcon(
|
||||
enabled,
|
||||
enabled->sizeValue(
|
||||
) | rpl::map([=](const QSize &size) {
|
||||
return QPoint(
|
||||
st::manageGroupButton.iconPosition.x(),
|
||||
(size.height() - iconHeight) / 2);
|
||||
}),
|
||||
iconHeight,
|
||||
list.front(),
|
||||
rpl::never<>(),
|
||||
rpl::never<>(),
|
||||
&enabled->lifetime());
|
||||
}
|
||||
const auto isGroup = args.isGroup;
|
||||
const auto enabled = isGroup
|
||||
? nullptr
|
||||
: container->add(object_ptr<Ui::SettingsButton>(
|
||||
container.get(),
|
||||
tr::lng_manage_peer_reactions_enable(),
|
||||
st::manageGroupNoIconButton.button));
|
||||
if (enabled) {
|
||||
enabled->toggleOn(state->anyToggled.value());
|
||||
enabled->toggledChanges(
|
||||
) | rpl::filter([=](bool value) {
|
||||
return (value != state->anyToggled.current());
|
||||
}) | rpl::start_to_stream(state->forceToggleAll, enabled->lifetime());
|
||||
enabled->toggleOn(rpl::single(optionInitial != Option::None));
|
||||
enabled->toggledValue(
|
||||
) | rpl::start_with_next([=](bool value) {
|
||||
state->selectorState = value
|
||||
? SelectorState::Active
|
||||
: SelectorState::Disabled;
|
||||
}, enabled->lifetime());
|
||||
}
|
||||
const auto group = std::make_shared<Ui::RadioenumGroup<Option>>(
|
||||
state->option.current());
|
||||
|
@ -138,8 +656,8 @@ void EditAllowedReactionsBox(
|
|||
}
|
||||
Unexpected("Option value in EditAllowedReactionsBox.");
|
||||
};
|
||||
Settings::AddSkip(container);
|
||||
Settings::AddDividerText(
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddDividerText(
|
||||
container,
|
||||
(isGroup
|
||||
? (state->option.value()
|
||||
|
@ -152,102 +670,106 @@ void EditAllowedReactionsBox(
|
|||
container,
|
||||
object_ptr<Ui::VerticalLayout>(container)));
|
||||
if (wrap) {
|
||||
wrap->toggleOn(state->option.value() | rpl::map(_1 == Option::Some));
|
||||
wrap->toggleOn(state->option.value(
|
||||
) | rpl::map(_1 == Option::Some) | rpl::before_next([=](bool some) {
|
||||
if (!some) {
|
||||
state->selectorState = SelectorState::Hidden;
|
||||
}
|
||||
}) | rpl::after_next([=](bool some) {
|
||||
if (some) {
|
||||
state->selectorState = SelectorState::Active;
|
||||
}
|
||||
}));
|
||||
wrap->finishAnimating();
|
||||
}
|
||||
const auto reactions = wrap ? wrap->entity() : container.get();
|
||||
|
||||
Settings::AddSkip(reactions);
|
||||
Settings::AddSubsectionTitle(
|
||||
reactions,
|
||||
(enabled
|
||||
? tr::lng_manage_peer_reactions_available()
|
||||
: tr::lng_manage_peer_reactions_some_title()));
|
||||
Ui::AddSkip(reactions);
|
||||
|
||||
const auto like = QString::fromUtf8("\xf0\x9f\x91\x8d");
|
||||
const auto dislike = QString::fromUtf8("\xf0\x9f\x91\x8e");
|
||||
const auto activeOnStart = [&](const ReactionId &id) {
|
||||
const auto inSome = ranges::contains(allowed.some, id);
|
||||
if (!isGroup) {
|
||||
return inSome || (allowed.type != AllowedReactionsType::Some);
|
||||
}
|
||||
const auto emoji = id.emoji();
|
||||
const auto isDefault = (emoji == like) || (emoji == dislike);
|
||||
return (allowed.type != AllowedReactionsType::Some)
|
||||
? isDefault
|
||||
: (inSome || (isDefault && allowed.some.empty()));
|
||||
};
|
||||
const auto add = [&](const Reaction &entry) {
|
||||
const auto button = Settings::AddButton(
|
||||
reactions,
|
||||
rpl::single(entry.title),
|
||||
st::manageGroupButton.button);
|
||||
AddReactionAnimatedIcon(
|
||||
button,
|
||||
button->sizeValue(
|
||||
) | rpl::map([=](const QSize &size) {
|
||||
return QPoint(
|
||||
st::editPeerReactionsIconLeft,
|
||||
(size.height() - iconHeight) / 2);
|
||||
}),
|
||||
iconHeight,
|
||||
entry,
|
||||
button->events(
|
||||
) | rpl::filter([=](not_null<QEvent*> event) {
|
||||
return event->type() == QEvent::Enter;
|
||||
}) | rpl::to_empty,
|
||||
rpl::never<>(),
|
||||
&button->lifetime());
|
||||
state->toggles.emplace(entry.id, button);
|
||||
button->toggleOn(rpl::single(
|
||||
activeOnStart(entry.id)
|
||||
) | rpl::then(enabled
|
||||
? (state->forceToggleAll.events() | rpl::type_erased())
|
||||
: rpl::never<bool>()
|
||||
));
|
||||
if (enabled) {
|
||||
button->toggledChanges(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
if (toggled) {
|
||||
state->anyToggled = true;
|
||||
} else if (collect().some.empty()) {
|
||||
state->anyToggled = false;
|
||||
}
|
||||
}, button->lifetime());
|
||||
const auto all = args.list;
|
||||
auto selected = (allowed.type != AllowedReactionsType::Some)
|
||||
? (all
|
||||
| ranges::views::transform(&Data::Reaction::id)
|
||||
| ranges::to_vector)
|
||||
: allowed.some;
|
||||
const auto changed = [=](
|
||||
std::vector<Data::ReactionId> chosen,
|
||||
bool hardLimitHit) {
|
||||
state->selected = std::move(chosen);
|
||||
state->customCount = ranges::count_if(
|
||||
state->selected,
|
||||
&Data::ReactionId::custom);
|
||||
if (hardLimitHit) {
|
||||
box->uiShow()->showToast(
|
||||
tr::lng_manage_peer_reactions_limit(tr::now));
|
||||
}
|
||||
};
|
||||
for (const auto &entry : list) {
|
||||
add(entry);
|
||||
}
|
||||
for (const auto &id : allowed.some) {
|
||||
if (const auto customId = id.custom()) {
|
||||
// Some possible forward compatibility.
|
||||
const auto button = Settings::AddButton(
|
||||
reactions,
|
||||
rpl::single(u"Custom reaction"_q),
|
||||
st::manageGroupButton.button);
|
||||
AddReactionCustomIcon(
|
||||
button,
|
||||
button->sizeValue(
|
||||
) | rpl::map([=](const QSize &size) {
|
||||
return QPoint(
|
||||
st::editPeerReactionsIconLeft,
|
||||
(size.height() - iconHeight) / 2);
|
||||
}),
|
||||
iconHeight,
|
||||
navigation->parentController(),
|
||||
customId,
|
||||
rpl::never<>(),
|
||||
&button->lifetime());
|
||||
state->toggles.emplace(id, button);
|
||||
button->toggleOn(rpl::single(true));
|
||||
changed(selected.empty() ? DefaultSelected() : std::move(selected), {});
|
||||
reactions->add(AddReactionsSelector(reactions, {
|
||||
.outer = box->getDelegate()->outerContainer(),
|
||||
.controller = args.navigation->parentController(),
|
||||
.title = (enabled
|
||||
? tr::lng_manage_peer_reactions_available()
|
||||
: tr::lng_manage_peer_reactions_some_title()),
|
||||
.list = all,
|
||||
.selected = state->selected,
|
||||
.callback = changed,
|
||||
.stateValue = state->selectorState.value(),
|
||||
.customAllowed = args.allowedCustomReactions,
|
||||
.customHardLimit = args.customReactionsHardLimit,
|
||||
.all = !args.isGroup,
|
||||
}), st::boxRowPadding);
|
||||
|
||||
box->setFocusCallback([=] {
|
||||
if (!wrap || state->option.current() == Option::Some) {
|
||||
state->selectorState.force_assign(SelectorState::Active);
|
||||
}
|
||||
});
|
||||
|
||||
if (!isGroup) {
|
||||
AddReactionsText(
|
||||
container,
|
||||
args.navigation,
|
||||
args.allowedCustomReactions,
|
||||
state->customCount.value(),
|
||||
args.askForBoosts);
|
||||
}
|
||||
const auto collect = [=] {
|
||||
auto result = AllowedReactions();
|
||||
if (isGroup
|
||||
? (state->option.current() == Option::Some)
|
||||
: (enabled->toggled())) {
|
||||
result.some = state->selected;
|
||||
}
|
||||
auto some = result.some;
|
||||
auto simple = all | ranges::views::transform(
|
||||
&Data::Reaction::id
|
||||
) | ranges::to_vector;
|
||||
ranges::sort(some);
|
||||
ranges::sort(simple);
|
||||
result.type = isGroup
|
||||
? (state->option.current() != Option::All
|
||||
? AllowedReactionsType::Some
|
||||
: AllowedReactionsType::All)
|
||||
: (some == simple)
|
||||
? AllowedReactionsType::Default
|
||||
: AllowedReactionsType::Some;
|
||||
return result;
|
||||
};
|
||||
|
||||
box->addButton(tr::lng_settings_save(), [=] {
|
||||
const auto result = collect();
|
||||
if (!isGroup) {
|
||||
const auto custom = ranges::count_if(
|
||||
result.some,
|
||||
&Data::ReactionId::custom);
|
||||
if (custom > args.allowedCustomReactions) {
|
||||
args.askForBoosts(custom);
|
||||
return;
|
||||
}
|
||||
}
|
||||
box->closeBox();
|
||||
callback(result);
|
||||
args.save(result);
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] {
|
||||
box->closeBox();
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
class PeerData;
|
||||
#include "data/data_peer.h"
|
||||
|
||||
namespace Data {
|
||||
struct Reaction;
|
||||
|
@ -22,13 +22,20 @@ namespace Window {
|
|||
class SessionNavigation;
|
||||
} // namespace Window
|
||||
|
||||
struct EditAllowedReactionsArgs {
|
||||
not_null<Window::SessionNavigation*> navigation;
|
||||
int allowedCustomReactions = 0;
|
||||
int customReactionsHardLimit = 0;
|
||||
bool isGroup = false;
|
||||
std::vector<Data::Reaction> list;
|
||||
Data::AllowedReactions allowed;
|
||||
Fn<void(int required)> askForBoosts;
|
||||
Fn<void(const Data::AllowedReactions &)> save;
|
||||
};
|
||||
|
||||
void EditAllowedReactionsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
bool isGroup,
|
||||
const std::vector<Data::Reaction> &list,
|
||||
const Data::AllowedReactions &allowed,
|
||||
Fn<void(const Data::AllowedReactions &)> callback);
|
||||
EditAllowedReactionsArgs &&args);
|
||||
|
||||
void SaveAllowedReactions(
|
||||
not_null<PeerData*> peer,
|
||||
|
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/unixtime.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "ui/round_rect.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/painter.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "base/weak_ptr.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
namespace Window {
|
||||
class SessionNavigation;
|
||||
|
|
|
@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
|
@ -44,7 +45,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -218,9 +218,9 @@ void Controller::createContent() {
|
|||
object_ptr<Ui::VerticalLayout>(_wrap.get())));
|
||||
const auto wrap = _controls.whoSendWrap->entity();
|
||||
|
||||
AddSkip(wrap);
|
||||
Ui::AddSkip(wrap);
|
||||
if (_dataSavedValue->hasLinkedChat) {
|
||||
AddSubsectionTitle(wrap, tr::lng_manage_peer_send_title());
|
||||
Ui::AddSubsectionTitle(wrap, tr::lng_manage_peer_send_title());
|
||||
|
||||
_controls.joinToWrite = wrap->add(EditPeerInfoBox::CreateButton(
|
||||
wrap,
|
||||
|
@ -264,16 +264,16 @@ void Controller::createContent() {
|
|||
_dataSavedValue->requestToJoin = toggled;
|
||||
}, wrap->lifetime());
|
||||
|
||||
AddSkip(wrap);
|
||||
AddDividerText(
|
||||
Ui::AddSkip(wrap);
|
||||
Ui::AddDividerText(
|
||||
wrap,
|
||||
rpl::conditional(
|
||||
std::move(joinToWrite),
|
||||
tr::lng_manage_peer_send_approve_members_about(),
|
||||
tr::lng_manage_peer_send_only_members_about()));
|
||||
}
|
||||
AddSkip(_wrap.get());
|
||||
AddSubsectionTitle(
|
||||
Ui::AddSkip(_wrap.get());
|
||||
Ui::AddSubsectionTitle(
|
||||
_wrap.get(),
|
||||
tr::lng_manage_peer_no_forwards_title());
|
||||
_controls.noForwards = _wrap->add(EditPeerInfoBox::CreateButton(
|
||||
|
@ -289,8 +289,8 @@ void Controller::createContent() {
|
|||
) | rpl::start_with_next([=](bool toggled) {
|
||||
_dataSavedValue->noForwards = toggled;
|
||||
}, _wrap->lifetime());
|
||||
AddSkip(_wrap.get());
|
||||
AddDividerText(
|
||||
Ui::AddSkip(_wrap.get());
|
||||
Ui::AddDividerText(
|
||||
_wrap.get(),
|
||||
(_isGroup
|
||||
? tr::lng_manage_peer_no_forwards_about
|
||||
|
@ -419,13 +419,13 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
|
|||
const auto container = result->entity();
|
||||
|
||||
using namespace Settings;
|
||||
AddSkip(container);
|
||||
Ui::AddSkip(container);
|
||||
container->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
tr::lng_create_group_link(),
|
||||
st::settingsSubsectionTitle),
|
||||
st::settingsSubsectionTitlePadding);
|
||||
st::defaultSubsectionTitle),
|
||||
st::defaultSubsectionTitlePadding);
|
||||
|
||||
const auto placeholder = container->add(
|
||||
object_ptr<Ui::RpWidget>(container),
|
||||
|
@ -453,7 +453,7 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
|
|||
|
||||
AddUsernameCheckLabel(container, _usernameCheckInfo.events());
|
||||
|
||||
AddDividerText(
|
||||
Ui::AddDividerText(
|
||||
container,
|
||||
tr::lng_create_channel_link_about());
|
||||
|
||||
|
@ -675,7 +675,7 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkBlock() {
|
|||
|
||||
using namespace Settings;
|
||||
if (_dataSavedValue) {
|
||||
AddSkip(container);
|
||||
Ui::AddSkip(container);
|
||||
|
||||
AddSubsectionTitle(container, tr::lng_create_permanent_link_title());
|
||||
}
|
||||
|
@ -686,9 +686,9 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkBlock() {
|
|||
_peer->session().user(),
|
||||
nullptr);
|
||||
|
||||
AddSkip(container);
|
||||
Ui::AddSkip(container);
|
||||
|
||||
AddDividerText(
|
||||
Ui::AddDividerText(
|
||||
container,
|
||||
((_peer->isMegagroup() || _peer->asChat())
|
||||
? tr::lng_group_invite_about_permanent_group()
|
||||
|
|
|
@ -14,10 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/layers/show.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::RichLangValue.
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
|
@ -25,7 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/wrap/vertical_layout_reorder.h"
|
||||
#include "styles/style_boxes.h" // contactsStatusFont.
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
@ -231,15 +231,15 @@ void UsernamesList::rebuild(const Data::Usernames &usernames) {
|
|||
_container = base::make_unique_q<Ui::VerticalLayout>(this);
|
||||
|
||||
{
|
||||
Settings::AddSkip(_container);
|
||||
Ui::AddSkip(_container);
|
||||
_container->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
_container,
|
||||
_peer->isSelf()
|
||||
? tr::lng_usernames_subtitle()
|
||||
: tr::lng_channel_usernames_subtitle(),
|
||||
st::settingsSubsectionTitle),
|
||||
st::settingsSubsectionTitlePadding);
|
||||
st::defaultSubsectionTitle),
|
||||
st::defaultSubsectionTitlePadding);
|
||||
}
|
||||
|
||||
const auto content = _container->add(
|
||||
|
@ -364,8 +364,8 @@ void UsernamesList::rebuild(const Data::Usernames &usernames) {
|
|||
}, content->lifetime());
|
||||
|
||||
{
|
||||
Settings::AddSkip(_container);
|
||||
Settings::AddDividerText(
|
||||
Ui::AddSkip(_container);
|
||||
Ui::AddDividerText(
|
||||
_container,
|
||||
_peer->isSelf()
|
||||
? tr::lng_usernames_description()
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
namespace style {
|
||||
struct ShortInfoCover;
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_domain.h"
|
||||
|
@ -27,8 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_folder.h"
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "settings/settings_premium.h" // ShowPremium.
|
||||
#include "base/unixtime.h"
|
||||
#include "apiwrap.h"
|
||||
#include "styles/style_premium.h"
|
||||
|
@ -48,11 +48,11 @@ struct InfographicDescriptor {
|
|||
bool complexRatio = false;
|
||||
};
|
||||
|
||||
void AddSubsectionTitle(
|
||||
void AddSubtitle(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
rpl::producer<QString> text) {
|
||||
const auto &subtitlePadding = st::settingsButton.padding;
|
||||
Settings::AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
container,
|
||||
std::move(text),
|
||||
{ 0, subtitlePadding.top(), 0, -subtitlePadding.bottom() });
|
||||
|
@ -395,7 +395,7 @@ void SimpleLimitBox(
|
|||
? box->setPinnedToTopContent(object_ptr<Ui::VerticalLayout>(box))
|
||||
: box->verticalLayout();
|
||||
|
||||
Settings::AddSkip(top, st::premiumInfographicPadding.top());
|
||||
Ui::AddSkip(top, st::premiumInfographicPadding.top());
|
||||
Ui::Premium::AddBubbleRow(
|
||||
top,
|
||||
st::defaultPremiumBubble,
|
||||
|
@ -406,7 +406,7 @@ void SimpleLimitBox(
|
|||
premiumPossible,
|
||||
descriptor.phrase,
|
||||
descriptor.icon);
|
||||
Settings::AddSkip(top, st::premiumLineTextSkip);
|
||||
Ui::AddSkip(top, st::premiumLineTextSkip);
|
||||
if (premiumPossible) {
|
||||
Ui::Premium::AddLimitRow(
|
||||
top,
|
||||
|
@ -417,7 +417,7 @@ void SimpleLimitBox(
|
|||
(descriptor.complexRatio
|
||||
? (float64(descriptor.current) / descriptor.premiumLimit)
|
||||
: Ui::Premium::kLimitRowRatio));
|
||||
Settings::AddSkip(top, st::premiumInfographicPadding.bottom());
|
||||
Ui::AddSkip(top, st::premiumInfographicPadding.bottom());
|
||||
}
|
||||
|
||||
box->setTitle(std::move(title));
|
||||
|
@ -446,8 +446,8 @@ void SimpleLimitBox(
|
|||
}
|
||||
|
||||
if (fixed) {
|
||||
Settings::AddSkip(top, st::settingsButton.padding.bottom());
|
||||
Settings::AddDivider(top);
|
||||
Ui::AddSkip(top, st::settingsButton.padding.bottom());
|
||||
Ui::AddDivider(top);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,7 +552,7 @@ void ChannelsLimitBox(
|
|||
{ defaultLimit, current, premiumLimit, &st::premiumIconGroups },
|
||||
true);
|
||||
|
||||
AddSubsectionTitle(box->verticalLayout(), tr::lng_channels_leave_title());
|
||||
AddSubtitle(box->verticalLayout(), tr::lng_channels_leave_title());
|
||||
|
||||
const auto delegate = box->lifetime().make_state<InactiveDelegate>();
|
||||
const auto controller = box->lifetime().make_state<InactiveController>(
|
||||
|
@ -642,7 +642,7 @@ void PublicLinksLimitBox(
|
|||
{ defaultLimit, current, premiumLimit, &st::premiumIconLinks },
|
||||
true);
|
||||
|
||||
AddSubsectionTitle(box->verticalLayout(), tr::lng_links_revoke_title());
|
||||
AddSubtitle(box->verticalLayout(), tr::lng_links_revoke_title());
|
||||
|
||||
const auto delegate = box->lifetime().make_state<InactiveDelegate>();
|
||||
const auto controller = box->lifetime().make_state<PublicsController>(
|
||||
|
@ -1067,7 +1067,7 @@ void AccountsLimitBox(
|
|||
const auto top = box->verticalLayout();
|
||||
const auto group = std::make_shared<Ui::RadiobuttonGroup>(0);
|
||||
|
||||
Settings::AddSkip(top, st::premiumInfographicPadding.top());
|
||||
Ui::AddSkip(top, st::premiumInfographicPadding.top());
|
||||
Ui::Premium::AddBubbleRow(
|
||||
top,
|
||||
st::defaultPremiumBubble,
|
||||
|
@ -1082,7 +1082,7 @@ void AccountsLimitBox(
|
|||
premiumPossible,
|
||||
std::nullopt,
|
||||
&st::premiumIconAccounts);
|
||||
Settings::AddSkip(top, st::premiumLineTextSkip);
|
||||
Ui::AddSkip(top, st::premiumLineTextSkip);
|
||||
if (premiumPossible) {
|
||||
Ui::Premium::AddLimitRow(
|
||||
top,
|
||||
|
@ -1090,7 +1090,7 @@ void AccountsLimitBox(
|
|||
(QString::number(std::max(current, defaultLimit) + 1)
|
||||
+ ((current + 1 == premiumLimit) ? "" : "+")),
|
||||
QString::number(defaultLimit));
|
||||
Settings::AddSkip(top, st::premiumInfographicPadding.bottom());
|
||||
Ui::AddSkip(top, st::premiumInfographicPadding.bottom());
|
||||
}
|
||||
box->setTitle(tr::lng_accounts_limit_title());
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/painter.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "lottie/lottie_single_player.h"
|
||||
#include "history/view/media/history_view_sticker.h"
|
||||
|
@ -93,6 +93,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
|
||||
[[nodiscard]] rpl::producer<QString> SectionTitle(PremiumPreview section) {
|
||||
switch (section) {
|
||||
case PremiumPreview::Wallpapers:
|
||||
return tr::lng_premium_summary_subtitle_wallpapers();
|
||||
case PremiumPreview::Stories:
|
||||
return tr::lng_premium_summary_subtitle_stories();
|
||||
case PremiumPreview::DoubleLimits:
|
||||
|
@ -127,6 +129,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
|
||||
[[nodiscard]] rpl::producer<QString> SectionAbout(PremiumPreview section) {
|
||||
switch (section) {
|
||||
case PremiumPreview::Wallpapers:
|
||||
return tr::lng_premium_summary_about_wallpapers();
|
||||
case PremiumPreview::Stories:
|
||||
return tr::lng_premium_summary_about_stories();
|
||||
case PremiumPreview::DoubleLimits:
|
||||
|
@ -471,6 +475,7 @@ struct VideoPreviewDocument {
|
|||
case PremiumPreview::ProfileBadge: return "profile_badge";
|
||||
case PremiumPreview::AnimatedUserpics: return "animated_userpics";
|
||||
case PremiumPreview::RealTimeTranslation: return "translations";
|
||||
case PremiumPreview::Wallpapers: return "wallpapers";
|
||||
}
|
||||
return "";
|
||||
}();
|
||||
|
@ -1488,7 +1493,7 @@ void UpgradedStoriesPreviewBox(
|
|||
st::defaultPremiumLimits,
|
||||
std::move(entries));
|
||||
|
||||
Settings::AddDividerText(
|
||||
Ui::AddDividerText(
|
||||
box->verticalLayout(),
|
||||
tr::lng_premium_stories_about_mobile());
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ enum class PremiumPreview {
|
|||
ProfileBadge,
|
||||
AnimatedUserpics,
|
||||
RealTimeTranslation,
|
||||
Wallpapers,
|
||||
|
||||
kCount,
|
||||
};
|
||||
|
|
|
@ -21,7 +21,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/chat/chat_theme.h"
|
||||
|
@ -33,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/animated_icon.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/section_widget.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
@ -64,8 +64,8 @@ PeerId GenerateUser(not_null<History*> history, const QString &name) {
|
|||
MTPEmojiStatus(),
|
||||
MTPVector<MTPUsername>(),
|
||||
MTPint(), // stories_max_id
|
||||
MTP_int(0), // color
|
||||
MTPlong())); // background_emoji_id
|
||||
MTPPeerColor(), // color
|
||||
MTPPeerColor())); // profile_color
|
||||
return peerId;
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ void AddMessage(
|
|||
object_ptr<Ui::RpWidget>(container),
|
||||
style::margins(
|
||||
0,
|
||||
st::settingsSectionSkip,
|
||||
st::defaultVerticalListSkip,
|
||||
0,
|
||||
st::settingsPrivacySkipTop));
|
||||
|
||||
|
@ -486,7 +486,7 @@ void ReactionsSettingsBox(
|
|||
auto idValue = state->selectedId.value();
|
||||
AddMessage(pinnedToTop, controller, std::move(idValue), box->width());
|
||||
|
||||
Settings::AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
pinnedToTop,
|
||||
tr::lng_settings_chat_reactions_subtitle());
|
||||
|
||||
|
@ -515,10 +515,10 @@ void ReactionsSettingsBox(
|
|||
}
|
||||
}
|
||||
for (const auto &r : list) {
|
||||
const auto button = Settings::AddButton(
|
||||
const auto button = container->add(object_ptr<Ui::SettingsButton>(
|
||||
container,
|
||||
rpl::single<QString>(base::duplicate(r.title)),
|
||||
st::settingsButton);
|
||||
st::settingsButton));
|
||||
|
||||
const auto premium = r.premium;
|
||||
if (premium && !premiumPossible) {
|
||||
|
|
|
@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "api/api_ringtones.h"
|
||||
#include "apiwrap.h"
|
||||
#include "base/base_file_utilities.h"
|
||||
#include "base/call_delayed.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "base/timer_rpl.h"
|
||||
|
@ -27,16 +26,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
@ -217,7 +215,7 @@ void RingtonesBox(
|
|||
}
|
||||
}, box->lifetime());
|
||||
|
||||
Settings::AddSubsectionTitle(
|
||||
Ui::AddSubsectionTitle(
|
||||
container,
|
||||
tr::lng_ringtones_box_cloud_subtitle());
|
||||
|
||||
|
@ -272,7 +270,7 @@ void RingtonesBox(
|
|||
rebuild();
|
||||
|
||||
const auto upload = box->addRow(
|
||||
Settings::CreateButton(
|
||||
Settings::CreateButtonWithIcon(
|
||||
container,
|
||||
tr::lng_ringtones_box_upload_button(),
|
||||
st::ringtonesBoxButton,
|
||||
|
@ -323,7 +321,7 @@ void RingtonesBox(
|
|||
});
|
||||
|
||||
box->addSkip(st::ringtonesBoxSkip);
|
||||
Settings::AddDividerText(container, tr::lng_ringtones_box_about());
|
||||
Ui::AddDividerText(container, tr::lng_ringtones_box_about());
|
||||
|
||||
box->addSkip(st::ringtonesBoxSkip);
|
||||
|
||||
|
|