diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index 7d51f89c0..178c021f0 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -549,6 +549,8 @@ PRIVATE
data/business/data_business_info.h
data/business/data_shortcut_messages.cpp
data/business/data_shortcut_messages.h
+ data/components/credits.cpp
+ data/components/credits.h
data/components/factchecks.cpp
data/components/factchecks.h
data/components/location_pickers.cpp
@@ -898,6 +900,8 @@ PRIVATE
history/view/history_view_message.cpp
history/view/history_view_message.h
history/view/history_view_object.h
+ history/view/history_view_paid_reaction_toast.cpp
+ history/view/history_view_paid_reaction_toast.h
history/view/history_view_pinned_bar.cpp
history/view/history_view_pinned_bar.h
history/view/history_view_pinned_section.cpp
@@ -1310,6 +1314,8 @@ PRIVATE
payments/payments_form.h
payments/payments_non_panel_process.cpp
payments/payments_non_panel_process.h
+ payments/payments_reaction_process.cpp
+ payments/payments_reaction_process.h
platform/linux/file_utilities_linux.cpp
platform/linux/file_utilities_linux.h
platform/linux/launcher_linux.cpp
@@ -1542,6 +1548,8 @@ PRIVATE
support/support_preload.h
support/support_templates.cpp
support/support_templates.h
+ ui/boxes/edit_invite_link_session.cpp
+ ui/boxes/edit_invite_link_session.h
ui/chat/attach/attach_item_single_file_preview.cpp
ui/chat/attach/attach_item_single_file_preview.h
ui/chat/attach/attach_item_single_media_preview.cpp
@@ -1896,7 +1904,7 @@ endif()
set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
-if (WIN32)
+if (WIN32 AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
target_link_libraries(Telegram
PRIVATE
delayimp
@@ -1993,7 +2001,7 @@ if (NOT DESKTOP_APP_DISABLE_AUTOUPDATE AND NOT build_macstore AND NOT build_wins
base/platform/win/base_windows_safe_library.h
)
target_include_directories(Updater PRIVATE ${lib_base_loc})
- if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
target_link_libraries(Updater
PRIVATE
delayimp
diff --git a/Telegram/Resources/art/bball_idle.tgs b/Telegram/Resources/animations/dice/bball_idle.tgs
similarity index 100%
rename from Telegram/Resources/art/bball_idle.tgs
rename to Telegram/Resources/animations/dice/bball_idle.tgs
diff --git a/Telegram/Resources/art/dart_idle.tgs b/Telegram/Resources/animations/dice/dart_idle.tgs
similarity index 100%
rename from Telegram/Resources/art/dart_idle.tgs
rename to Telegram/Resources/animations/dice/dart_idle.tgs
diff --git a/Telegram/Resources/art/dice_idle.tgs b/Telegram/Resources/animations/dice/dice_idle.tgs
similarity index 100%
rename from Telegram/Resources/art/dice_idle.tgs
rename to Telegram/Resources/animations/dice/dice_idle.tgs
diff --git a/Telegram/Resources/art/fball_idle.tgs b/Telegram/Resources/animations/dice/fball_idle.tgs
similarity index 100%
rename from Telegram/Resources/art/fball_idle.tgs
rename to Telegram/Resources/animations/dice/fball_idle.tgs
diff --git a/Telegram/Resources/art/slot_0_idle.tgs b/Telegram/Resources/animations/dice/slot_0_idle.tgs
similarity index 100%
rename from Telegram/Resources/art/slot_0_idle.tgs
rename to Telegram/Resources/animations/dice/slot_0_idle.tgs
diff --git a/Telegram/Resources/art/slot_1_idle.tgs b/Telegram/Resources/animations/dice/slot_1_idle.tgs
similarity index 100%
rename from Telegram/Resources/art/slot_1_idle.tgs
rename to Telegram/Resources/animations/dice/slot_1_idle.tgs
diff --git a/Telegram/Resources/art/slot_2_idle.tgs b/Telegram/Resources/animations/dice/slot_2_idle.tgs
similarity index 100%
rename from Telegram/Resources/art/slot_2_idle.tgs
rename to Telegram/Resources/animations/dice/slot_2_idle.tgs
diff --git a/Telegram/Resources/art/slot_back.tgs b/Telegram/Resources/animations/dice/slot_back.tgs
similarity index 100%
rename from Telegram/Resources/art/slot_back.tgs
rename to Telegram/Resources/animations/dice/slot_back.tgs
diff --git a/Telegram/Resources/art/slot_pull.tgs b/Telegram/Resources/animations/dice/slot_pull.tgs
similarity index 100%
rename from Telegram/Resources/art/slot_pull.tgs
rename to Telegram/Resources/animations/dice/slot_pull.tgs
diff --git a/Telegram/Resources/art/winners.tgs b/Telegram/Resources/animations/dice/winners.tgs
similarity index 100%
rename from Telegram/Resources/art/winners.tgs
rename to Telegram/Resources/animations/dice/winners.tgs
diff --git a/Telegram/Resources/animations/star_reaction/appear.tgs b/Telegram/Resources/animations/star_reaction/appear.tgs
new file mode 100644
index 000000000..e47d5492e
Binary files /dev/null and b/Telegram/Resources/animations/star_reaction/appear.tgs differ
diff --git a/Telegram/Resources/animations/star_reaction/center.tgs b/Telegram/Resources/animations/star_reaction/center.tgs
new file mode 100644
index 000000000..61f153854
Binary files /dev/null and b/Telegram/Resources/animations/star_reaction/center.tgs differ
diff --git a/Telegram/Resources/animations/star_reaction/effect1.tgs b/Telegram/Resources/animations/star_reaction/effect1.tgs
new file mode 100644
index 000000000..f31897de5
Binary files /dev/null and b/Telegram/Resources/animations/star_reaction/effect1.tgs differ
diff --git a/Telegram/Resources/animations/star_reaction/effect2.tgs b/Telegram/Resources/animations/star_reaction/effect2.tgs
new file mode 100644
index 000000000..2bbeb3b7a
Binary files /dev/null and b/Telegram/Resources/animations/star_reaction/effect2.tgs differ
diff --git a/Telegram/Resources/animations/star_reaction/effect3.tgs b/Telegram/Resources/animations/star_reaction/effect3.tgs
new file mode 100644
index 000000000..983b41b7b
Binary files /dev/null and b/Telegram/Resources/animations/star_reaction/effect3.tgs differ
diff --git a/Telegram/Resources/animations/star_reaction/select.tgs b/Telegram/Resources/animations/star_reaction/select.tgs
new file mode 100644
index 000000000..cf8fc6758
Binary files /dev/null and b/Telegram/Resources/animations/star_reaction/select.tgs differ
diff --git a/Telegram/Resources/animations/star_reaction/toast.tgs b/Telegram/Resources/animations/star_reaction/toast.tgs
new file mode 100644
index 000000000..abfb9602c
Binary files /dev/null and b/Telegram/Resources/animations/star_reaction/toast.tgs differ
diff --git a/Telegram/Resources/animations/stats_boosts.tgs b/Telegram/Resources/animations/stats_boosts.tgs
new file mode 100644
index 000000000..10ba08cf2
Binary files /dev/null and b/Telegram/Resources/animations/stats_boosts.tgs differ
diff --git a/Telegram/Resources/animations/stats_earn.tgs b/Telegram/Resources/animations/stats_earn.tgs
new file mode 100644
index 000000000..d66fa990a
Binary files /dev/null and b/Telegram/Resources/animations/stats_earn.tgs differ
diff --git a/Telegram/Resources/icons/chat/mini_stars.png b/Telegram/Resources/icons/chat/mini_stars.png
new file mode 100644
index 000000000..f34408394
Binary files /dev/null and b/Telegram/Resources/icons/chat/mini_stars.png differ
diff --git a/Telegram/Resources/icons/chat/mini_stars@2x.png b/Telegram/Resources/icons/chat/mini_stars@2x.png
new file mode 100644
index 000000000..d7d61cf6a
Binary files /dev/null and b/Telegram/Resources/icons/chat/mini_stars@2x.png differ
diff --git a/Telegram/Resources/icons/chat/mini_stars@3x.png b/Telegram/Resources/icons/chat/mini_stars@3x.png
new file mode 100644
index 000000000..4a754e21a
Binary files /dev/null and b/Telegram/Resources/icons/chat/mini_stars@3x.png differ
diff --git a/Telegram/Resources/icons/info/edit/links_subscription.svg b/Telegram/Resources/icons/info/edit/links_subscription.svg
new file mode 100644
index 000000000..2d2d0c3fb
--- /dev/null
+++ b/Telegram/Resources/icons/info/edit/links_subscription.svg
@@ -0,0 +1,36 @@
+
+
\ No newline at end of file
diff --git a/Telegram/Resources/langs/cloud_lang.strings b/Telegram/Resources/langs/cloud_lang.strings
index c9d4af958..16e9ea357 100644
--- a/Telegram/Resources/langs/cloud_lang.strings
+++ b/Telegram/Resources/langs/cloud_lang.strings
@@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"cloud_lng_forwarded_psa_covid" = "COVID-19 Notification from {channel}";
"cloud_lng_tooltip_psa_covid" = "This message provides you with a public service announcement in relation to the ongoing COVID-19 pandemic. Learn more about this initiative at https://telegram.org/blog/coronavirus";
+"cloud_lng_topup_purpose_subs" = "Buy **Stars** to keep your channel subscriptions.";
+
"cloud_lng_passport_in_ar" = "Arabic";
"cloud_lng_passport_in_az" = "Azerbaijani";
"cloud_lng_passport_in_bg" = "Bulgarian";
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 9eb209ceb..2d5d49f2c 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -1315,6 +1315,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_bot_settings" = "Bot Settings";
"lng_profile_bot_help" = "Bot Help";
"lng_profile_bot_privacy" = "Bot Privacy Policy";
+"lng_profile_bot_privacy_url" = "https://telegram.org/privacy-tpa";
"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";
@@ -1550,6 +1551,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_reactions_max_slider#other" = "{count} reactions per post";
"lng_manage_peer_reactions_max_about" = "Limit the number of different reactions that can be added to a post, including already published ones.";
+"lng_manage_peer_reactions_paid" = "Enable Paid Reactions";
+"lng_manage_peer_reactions_paid_about" = "Switch this on to let your subscribers set paid reactions with Telegram Stars, which you will be able to withdraw later as TON. {link}";
+"lng_manage_peer_reactions_paid_link" = "Learn more >";
+
"lng_manage_peer_antispam" = "Aggressive Anti-Spam";
"lng_manage_peer_antispam_about" = "Telegram will filter more spam but may occasionally affect ordinary messages. You can report False Positives in Recent Actions.";
"lng_manage_peer_antispam_not_enough#one" = "Aggressive filtering can be enabled only in groups with more than **{count} member**.";
@@ -1943,6 +1948,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_invite_members#other" = "{count} members, among them:";
"lng_channel_invite_private" = "This channel is private.\nPlease join it to continue viewing its content.";
+"lng_channel_invite_subscription_button" = "Subscribe";
+"lng_channel_invite_subscription_title" = "Subscribe to the Channel";
+"lng_channel_invite_subscription_about" = "Do you want to subscribe for {channel} for {price} per month?";
+"lng_channel_invite_subscription_terms" = "By subscribing you agree to the {link}.";
+
"lng_group_invite_create" = "Create an invite link";
"lng_group_invite_about_new" = "Your previous link will be deactivated and we'll generate a new invite link for you.";
"lng_group_invite_copied" = "Invite link copied to clipboard.";
@@ -2017,6 +2027,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_invite_about_no_approve" = "New users will be able to join the group without being approved by the admins.";
"lng_group_invite_about_approve_channel" = "New users will be able to join the channel only after having been approved by the admins.";
"lng_group_invite_about_no_approve_channel" = "New users will be able to join the channel without being approved by the admins.";
+"lng_group_invite_subscription" = "Require Monthly Fee";
+"lng_group_invite_subscription_ph" = "Stars Amount per month";
+"lng_group_invite_subscription_price" = "~{cost} / month";
+"lng_group_invite_subscription_toast" = "Sorry, you cannot change the number of Stars for an already created invite link.";
+"lng_group_invite_subscription_about" = "Charge a subscription fee from people joining your channel via this link. {link}";
+"lng_group_invite_subscription_about_link" = "Learn more {emoji}";
+"lng_group_invite_subscription_about_url" = "https://telegram.org/tos/stars";
+"lng_group_invite_subscription_info_subtitle" = "Subscription fee";
+"lng_group_invite_subscription_info_title" = "{emoji} {price} / month {multiplier} {total}";
+"lng_group_invite_subscription_info_title_none" = "{emoji} {price} / month";
+"lng_group_invite_subscription_info_about" = "you get approximately {total} montly";
+"lng_group_invite_joined_right" = "per month";
+"lng_group_invite_joined_status" = "joined {date}";
+"lng_group_invite_joined_row_subscriber" = "Subscriber";
+"lng_group_invite_joined_row_date" = "Subscribed";
"lng_group_request_to_join" = "Request to Join";
"lng_group_request_about" = "This group accepts new members only after they are approved by its admins.";
@@ -2352,6 +2377,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_credits_box_out_sure#other" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Stars**?";
"lng_credits_box_out_media#one" = "Do you want to unlock {media} in {chat} for **{count} Star**?";
"lng_credits_box_out_media#other" = "Do you want to unlock {media} in {chat} for **{count} Stars**?";
+"lng_credits_box_out_media_user#one" = "Do you want to unlock {media} from {user} for **{count} Star**?";
+"lng_credits_box_out_media_user#other" = "Do you want to unlock {media} from {user} for **{count} Stars**?";
"lng_credits_box_out_photo" = "a photo";
"lng_credits_box_out_photos#one" = "{count} photo";
"lng_credits_box_out_photos#other" = "{count} photos";
@@ -2366,6 +2393,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_credits_media_done_title" = "Media Unlocked";
"lng_credits_media_done_text#one" = "**{count} Star** transferred to {chat}.";
"lng_credits_media_done_text#other" = "**{count} Stars** transferred to {chat}.";
+"lng_credits_media_done_text_user#one" = "**{count} Star** transferred to {user}.";
+"lng_credits_media_done_text_user#other" = "**{count} Stars** transferred to {user}.";
"lng_credits_summary_in_toast_title" = "Stars Acquired";
"lng_credits_summary_in_toast_about#one" = "**{count}** Star added to your balance.";
"lng_credits_summary_in_toast_about#other" = "**{count}** Stars added to your balance.";
@@ -2392,10 +2421,42 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_credits_box_history_entry_media" = "Media";
"lng_credits_box_history_entry_about" = "You can dispute this transaction {link}.";
"lng_credits_box_history_entry_about_link" = "here";
+"lng_credits_box_history_entry_reaction_name" = "Star Reaction";
+"lng_credits_box_history_entry_subscription" = "Monthly subscription fee";
+
+"lng_credits_subscription_section" = "My subscriptions";
+"lng_credits_box_subscription_title" = "Subscription";
+"lng_credits_subscription_subtitle" = "{emoji} {cost} / month";
+"lng_credits_subscriber_subtitle" = "appx. {total} per month";
+
+"lng_credits_subscription_row_to" = "Subscription";
+"lng_credits_subscription_row_from" = "Subscribed";
+
+"lng_credits_subscription_row_next_on" = "Renews";
+"lng_credits_subscription_row_next_off" = "Expires";
+"lng_credits_subscription_row_next_none" = "Expired";
+
+"lng_credits_subscription_on_button" = "Cancel Subscription";
+"lng_credits_subscription_on_about" = "If you cancel now, you will still be able to access your subscription until {date}.";
+
+"lng_credits_subscription_off_button" = "Renew Subscription";
+"lng_credits_subscription_off_about" = "You have cancelled your subscription.";
+
+"lng_credits_subscription_status_on" = "renews on {date}";
+"lng_credits_subscription_status_off" = "expires on {date}";
+"lng_credits_subscription_status_none" = "expired on {date}";
+"lng_credits_subscription_status_off_right" = "cancelled";
+"lng_credits_subscription_status_none_right" = "expired";
+
"lng_credits_small_balance_title#one" = "{count} Star Needed";
"lng_credits_small_balance_title#other" = "{count} Stars Needed";
"lng_credits_small_balance_about" = "Buy **Stars** and use them on **{bot}** and other miniapps.";
+"lng_credits_small_balance_reaction" = "Buy **Stars** and send them to {channel} to support their posts.";
+"lng_credits_small_balance_subscribe" = "Buy **Stars** and subscribe to **{channel}** and other channels.";
+"lng_credits_small_balance_fallback" = "Buy **Stars** to unlock content and services on Telegram.";
"lng_credits_purchase_blocked" = "Sorry, you can't purchase this item with Telegram Stars.";
+"lng_credits_enough" = "You have enough stars at the moment. {link}";
+"lng_credits_enough_link" = "Buy anyway";
"lng_credits_gift_title" = "Gift Telegram Stars";
@@ -3188,6 +3249,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_bot_add_to_side_menu" = "{bot} asks your permission to be added as an option to your main menu so you can access it any time.";
"lng_bot_add_to_side_menu_done" = "Bot added to the main menu.";
"lng_bot_no_scan_qr" = "QR Codes for bots are not supported on Desktop. Please use one of Telegram's mobile apps.";
+"lng_bot_no_share_story" = "Sharing to Stories is not supported on Desktop. Please use one of Telegram's mobile apps.";
"lng_bot_click_to_start" = "Click here to use this bot.";
"lng_bot_status_users#one" = "{count} user";
"lng_bot_status_users#other" = "{count} users";
@@ -3412,6 +3474,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_paid_about_link_url" = "https://telegram.org/blog/telegram-stars";
"lng_paid_price" = "Unlock for {price}";
+"lng_paid_react_title" = "Star Reaction";
+"lng_paid_react_about" = "Choose how many **Stars** you want to send to {channel} to support this post.";
+"lng_paid_react_already#one" = "You sent **{count} Star** to support this post.";
+"lng_paid_react_already#other" = "You sent **{count} Stars** to support this post.";
+"lng_paid_react_top_title" = "Top Senders";
+"lng_paid_react_send" = "Send {price}";
+"lng_paid_react_agree" = "By sending stars, you agree to the {link}.";
+"lng_paid_react_agree_link" = "Terms of Service";
+"lng_paid_react_toast#one" = "Star Sent!";
+"lng_paid_react_toast#other" = "Stars Sent!";
+"lng_paid_react_toast_text#one" = "You reacted with **{count} Star**.";
+"lng_paid_react_toast_text#other" = "You reacted with **{count} Stars**.";
+"lng_paid_react_undo" = "Undo";
+"lng_paid_react_show_in_top" = "Show me in Top Senders";
+"lng_paid_react_anonymous" = "Anonymous";
+
+"lng_sensitive_tag" = "18+";
+"lng_sensitive_title" = "18+";
+"lng_sensitive_text" = "This media may contain sensitive content suitable only for adults. Do you still want to view it?";
+"lng_sensitive_always" = "Always show 18+ media";
+"lng_sensitive_view" = "View Anyway";
+"lng_sensitive_toast" = "You can update the visibility of sensitive media in **Settings > Chat Settings > Sensitive content**";
+
"lng_translate_show_original" = "Show Original";
"lng_translate_bar_to" = "Translate to {name}";
"lng_translate_bar_to_other" = "Translate to {name}";
@@ -3516,6 +3601,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_edit_channel_title" = "Edit channel";
"lng_edit_bot_title" = "Edit bot";
"lng_edit_sign_messages" = "Sign messages";
+"lng_edit_sign_messages_about" = "Add names of admins to the messages they post.";
+"lng_edit_sign_profiles" = "Show authors' profiles";
+"lng_edit_sign_profiles_about" = "Add names and photos of admins to the messages they post, linking to their profiles.";
"lng_edit_group" = "Edit group";
"lng_edit_channel_color" = "Change name color";
"lng_edit_channel_level_min" = "Level 1+";
@@ -4305,6 +4393,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_invites_disabled" = "{from} disabled group invites";
"lng_admin_log_signatures_enabled" = "{from} enabled signatures";
"lng_admin_log_signatures_disabled" = "{from} disabled signatures";
+"lng_admin_log_signature_profiles_enabled" = "{from} enabled showing authors' profiles";
+"lng_admin_log_signature_profiles_disabled" = "{from} disabled showing authors' profiles";
"lng_admin_log_forwards_enabled" = "{from} allowed content copying";
"lng_admin_log_forwards_disabled" = "{from} restricted content copying";
"lng_admin_log_history_made_hidden" = "{from} made group history hidden for new members";
@@ -5179,6 +5269,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stats_loading" = "Loading stats...";
"lng_stats_loading_subtext" = "Please wait a few moments while we generate your stats.";
+"lng_stats_boosts_loading" = "Loading boosts list...";
+"lng_stats_boosts_loading_subtext" = "Please wait a few moments while we generate your stats.";
+"lng_stats_earn_loading" = "Loading rewards info...";
+"lng_stats_earn_loading_subtext" = "Please wait a few moments while we generate your stats.";
"lng_chart_title_member_count" = "Growth";
"lng_chart_title_join" = "Followers";
diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc
index 16920ae4d..ac6ff1dbf 100644
--- a/Telegram/Resources/qrc/telegram/animations.qrc
+++ b/Telegram/Resources/qrc/telegram/animations.qrc
@@ -11,20 +11,41 @@
../../animations/ttl.tgs
../../animations/discussion.tgs
../../animations/stats.tgs
+ ../../animations/stats_boosts.tgs
+ ../../animations/stats_earn.tgs
../../animations/voice_ttl_idle.tgs
../../animations/voice_ttl_start.tgs
../../animations/palette.tgs
../../animations/sleep.tgs
- ../../animations/greeting.tgs
- ../../animations/location.tgs
- ../../animations/robot.tgs
- ../../animations/writing.tgs
- ../../animations/hours.tgs
- ../../animations/phone.tgs
+ ../../animations/greeting.tgs
+ ../../animations/location.tgs
+ ../../animations/robot.tgs
+ ../../animations/writing.tgs
+ ../../animations/hours.tgs
+ ../../animations/phone.tgs
../../animations/chat_link.tgs
../../animations/collectible_username.tgs
../../animations/collectible_phone.tgs
../../animations/search.tgs
../../animations/noresults.tgs
+
+ ../../animations/dice/dice_idle.tgs
+ ../../animations/dice/dart_idle.tgs
+ ../../animations/dice/bball_idle.tgs
+ ../../animations/dice/fball_idle.tgs
+ ../../animations/dice/slot_0_idle.tgs
+ ../../animations/dice/slot_1_idle.tgs
+ ../../animations/dice/slot_2_idle.tgs
+ ../../animations/dice/slot_back.tgs
+ ../../animations/dice/slot_pull.tgs
+ ../../animations/dice/winners.tgs
+
+ ../../animations/star_reaction/appear.tgs
+ ../../animations/star_reaction/center.tgs
+ ../../animations/star_reaction/select.tgs
+ ../../animations/star_reaction/toast.tgs
+ ../../animations/star_reaction/effect1.tgs
+ ../../animations/star_reaction/effect2.tgs
+ ../../animations/star_reaction/effect3.tgs
diff --git a/Telegram/Resources/qrc/telegram/telegram.qrc b/Telegram/Resources/qrc/telegram/telegram.qrc
index b6caf7642..ebc75d326 100644
--- a/Telegram/Resources/qrc/telegram/telegram.qrc
+++ b/Telegram/Resources/qrc/telegram/telegram.qrc
@@ -7,16 +7,6 @@
../../art/logo_256.png
../../art/logo_256_no_margin.png
../../art/themeimage.jpg
- ../../art/dice_idle.tgs
- ../../art/dart_idle.tgs
- ../../art/bball_idle.tgs
- ../../art/fball_idle.tgs
- ../../art/slot_0_idle.tgs
- ../../art/slot_1_idle.tgs
- ../../art/slot_2_idle.tgs
- ../../art/slot_back.tgs
- ../../art/slot_pull.tgs
- ../../art/winners.tgs
../../day-blue.tdesktop-theme
../../night.tdesktop-theme
../../night-green.tdesktop-theme
@@ -40,6 +30,7 @@
../../art/topic_icons/red.svg
../../art/topic_icons/gray.svg
../../art/topic_icons/general.svg
+ ../../icons/info/edit/links_subscription.svg
../../icons/calls/hands.lottie
diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml
index 89f5f8761..3a9d2ec92 100644
--- a/Telegram/Resources/uwp/AppX/AppxManifest.xml
+++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml
@@ -10,7 +10,7 @@
+ Version="5.4.1.0" />
Telegram Desktop
Telegram Messenger LLP
@@ -37,8 +37,8 @@
-
+
box,
+ not_null session,
+ const QString &hash,
+ const MTPDchatInvite *data) {
+ box->setWidth(st::boxWideWidth);
+ const auto amount = data->vsubscription_pricing()->data().vamount().v;
+ const auto formId = data->vsubscription_form_id()->v;
+ const auto name = qs(data->vtitle());
+ const auto maybePhoto = session->data().processPhoto(data->vphoto());
+ const auto photo = maybePhoto->isNull() ? nullptr : maybePhoto.get();
+
+ struct State final {
+ std::shared_ptr photoMedia;
+ std::unique_ptr photoEmpty;
+
+ std::optional api;
+ Ui::RpWidget* saveButton = nullptr;
+ rpl::variable loading;
+ };
+ const auto state = box->lifetime().make_state();
+
+ const auto content = box->verticalLayout();
+
+ Ui::AddSkip(content, st::confirmInvitePhotoTop);
+ const auto userpicWrap = content->add(
+ object_ptr>(
+ content,
+ object_ptr(content)));
+ const auto userpic = userpicWrap->entity();
+ const auto photoSize = st::confirmInvitePhotoSize;
+ userpic->resize(Size(photoSize));
+ const auto options = Images::Option::RoundCircle;
+ userpic->paintRequest(
+ ) | rpl::start_with_next([=, small = Data::PhotoSize::Small] {
+ auto p = QPainter(userpic);
+ if (state->photoMedia) {
+ if (const auto image = state->photoMedia->image(small)) {
+ p.drawPixmap(
+ 0,
+ 0,
+ image->pix(Size(photoSize), { .options = options }));
+ }
+ } else if (state->photoEmpty) {
+ state->photoEmpty->paintCircle(
+ p,
+ 0,
+ 0,
+ userpic->width(),
+ photoSize);
+ }
+ }, userpicWrap->lifetime());
+ userpicWrap->setAttribute(Qt::WA_TransparentForMouseEvents);
+ if (photo) {
+ state->photoMedia = photo->createMediaView();
+ state->photoMedia->wanted(Data::PhotoSize::Small, Data::FileOrigin());
+ if (!state->photoMedia->image(Data::PhotoSize::Small)) {
+ session->downloaderTaskFinished(
+ ) | rpl::start_with_next([=] {
+ userpic->update();
+ }, userpicWrap->entity()->lifetime());
+ }
+ } else {
+ state->photoEmpty = std::make_unique(
+ Ui::EmptyUserpic::UserpicColor(0),
+ name);
+ }
+ Ui::AddSkip(content);
+ Ui::AddSkip(content);
+
+ {
+ const auto widget = Ui::CreateChild(content);
+ using ColoredMiniStars = Ui::Premium::ColoredMiniStars;
+ const auto stars = widget->lifetime().make_state(
+ widget,
+ false,
+ Ui::Premium::MiniStars::Type::BiStars);
+ stars->setColorOverride(Ui::Premium::CreditsIconGradientStops());
+ widget->resize(
+ st::boxWideWidth - photoSize,
+ photoSize * 2);
+ content->sizeValue(
+ ) | rpl::start_with_next([=](const QSize &size) {
+ widget->moveToLeft(photoSize / 2, 0);
+ const auto starsRect = Rect(widget->size());
+ stars->setPosition(starsRect.topLeft());
+ stars->setSize(starsRect.size());
+ widget->lower();
+ }, widget->lifetime());
+ widget->paintRequest(
+ ) | rpl::start_with_next([=](const QRect &r) {
+ auto p = QPainter(widget);
+ p.fillRect(r, Qt::transparent);
+ stars->paint(p);
+ }, widget->lifetime());
+ }
+
+ box->addRow(
+ object_ptr>(
+ box,
+ object_ptr(
+ box,
+ tr::lng_channel_invite_subscription_title(),
+ st::inviteLinkSubscribeBoxTitle)));
+ box->addRow(
+ object_ptr>(
+ box,
+ object_ptr(
+ box,
+ tr::lng_channel_invite_subscription_about(
+ lt_channel,
+ rpl::single(Ui::Text::Bold(name)),
+ lt_price,
+ tr::lng_credits_summary_options_credits(
+ lt_count,
+ rpl::single(amount) | tr::to_count(),
+ Ui::Text::Bold),
+ Ui::Text::WithEntities),
+ st::inviteLinkSubscribeBoxAbout)));
+ Ui::AddSkip(content);
+ box->addRow(
+ object_ptr>(
+ box,
+ object_ptr(
+ box,
+ tr::lng_channel_invite_subscription_terms(
+ lt_link,
+ rpl::combine(
+ tr::lng_paid_react_agree_link(),
+ tr::lng_group_invite_subscription_about_url()
+ ) | rpl::map([](const QString &text, const QString &url) {
+ return Ui::Text::Link(text, url);
+ }),
+ Ui::Text::RichLangValue),
+ st::inviteLinkSubscribeBoxTerms)));
+
+ {
+ const auto balance = Settings::AddBalanceWidget(
+ content,
+ session->credits().balanceValue(),
+ true);
+ session->credits().load(true);
+
+ rpl::combine(
+ balance->sizeValue(),
+ content->sizeValue()
+ ) | rpl::start_with_next([=](const QSize &, const QSize &) {
+ balance->moveToRight(
+ st::creditsHistoryRightSkip * 2,
+ st::creditsHistoryRightSkip);
+ balance->update();
+ }, balance->lifetime());
+ }
+
+ const auto sendCredits = [=, weak = Ui::MakeWeak(box)] {
+ const auto show = box->uiShow();
+ const auto buttonWidth = state->saveButton
+ ? state->saveButton->width()
+ : 0;
+ state->api->request(
+ MTPpayments_SendStarsForm(
+ MTP_flags(0),
+ MTP_long(formId),
+ MTP_inputInvoiceChatInviteSubscription(MTP_string(hash)))
+ ).done([=](const MTPpayments_PaymentResult &result) {
+ state->api = std::nullopt;
+ state->loading.force_assign(false);
+ result.match([&](const MTPDpayments_paymentResult &data) {
+ session->api().applyUpdates(data.vupdates());
+ }, [](const MTPDpayments_paymentVerificationNeeded &data) {
+ });
+ if (weak) {
+ box->closeBox();
+ }
+ }).fail([=](const MTP::Error &error) {
+ const auto id = error.type();
+ if (weak) {
+ state->api = std::nullopt;
+ }
+ show->showToast(id);
+ state->loading.force_assign(false);
+ }).send();
+ if (state->saveButton) {
+ state->saveButton->resizeToWidth(buttonWidth);
+ }
+ };
+
+ auto confirmText = tr::lng_channel_invite_subscription_button();
+ state->saveButton = box->addButton(std::move(confirmText), [=] {
+ if (state->api) {
+ return;
+ }
+ state->api.emplace(&session->mtp());
+ state->loading.force_assign(true);
+
+ const auto done = [=](Settings::SmallBalanceResult result) {
+ if (result == Settings::SmallBalanceResult::Success
+ || result == Settings::SmallBalanceResult::Already) {
+ sendCredits();
+ } else {
+ state->api = std::nullopt;
+ state->loading.force_assign(false);
+ }
+ };
+ Settings::MaybeRequestBalanceIncrease(
+ Main::MakeSessionShow(box->uiShow(), session),
+ amount,
+ Settings::SmallBalanceSubscription{ .name = name },
+ done);
+ });
+
+ if (const auto saveButton = state->saveButton) {
+ using namespace Info::Statistics;
+ const auto loadingAnimation = InfiniteRadialAnimationWidget(
+ saveButton,
+ saveButton->height() / 2,
+ &st::editStickerSetNameLoading);
+ AddChildToWidgetCenter(saveButton, loadingAnimation);
+ loadingAnimation->showOn(
+ state->loading.value() | rpl::map(rpl::mappers::_1));
+ }
+ box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
+}
+
} // namespace
void CheckChatInvite(
not_null controller,
const QString &hash,
- ChannelData *invitePeekChannel) {
+ ChannelData *invitePeekChannel,
+ Fn loaded) {
const auto session = &controller->session();
const auto weak = base::make_weak(controller);
session->api().checkChatInvite(hash, [=](const MTPChatInvite &result) {
@@ -114,6 +352,9 @@ void CheckChatInvite(
if (!strong) {
return;
}
+ if (loaded) {
+ loaded();
+ }
Core::App().hideMediaView();
const auto show = [&](not_null chat) {
const auto way = Window::SectionShow::Way::Forward;
@@ -125,11 +366,23 @@ void CheckChatInvite(
};
result.match([=](const MTPDchatInvite &data) {
const auto isGroup = !data.is_broadcast();
- const auto box = strong->show(Box(
- session,
- data,
- invitePeekChannel,
- [=] { SubmitChatInvite(weak, session, hash, isGroup); }));
+ const auto hasPricing = !!data.vsubscription_pricing();
+ if (hasPricing && !data.vsubscription_form_id()) {
+ strong->uiShow()->showToast(
+ tr::lng_confirm_phone_link_invalid(tr::now));
+ return;
+ }
+ const auto box = hasPricing
+ ? strong->show(Box(
+ ConfirmSubscriptionBox,
+ session,
+ hash,
+ &data))
+ : strong->show(Box(
+ session,
+ data,
+ invitePeekChannel,
+ [=] { SubmitChatInvite(weak, session, hash, isGroup); }));
if (invitePeekChannel) {
box->boxClosing(
) | rpl::filter([=] {
diff --git a/Telegram/SourceFiles/api/api_chat_invite.h b/Telegram/SourceFiles/api/api_chat_invite.h
index c8d99548c..94eeab5e9 100644
--- a/Telegram/SourceFiles/api/api_chat_invite.h
+++ b/Telegram/SourceFiles/api/api_chat_invite.h
@@ -38,7 +38,8 @@ namespace Api {
void CheckChatInvite(
not_null controller,
const QString &hash,
- ChannelData *invitePeekChannel = nullptr);
+ ChannelData *invitePeekChannel = nullptr,
+ Fn loaded = nullptr);
} // namespace Api
diff --git a/Telegram/SourceFiles/api/api_credits.cpp b/Telegram/SourceFiles/api/api_credits.cpp
index 727cee565..d0dc717ea 100644
--- a/Telegram/SourceFiles/api/api_credits.cpp
+++ b/Telegram/SourceFiles/api/api_credits.cpp
@@ -94,32 +94,70 @@ constexpr auto kTransactionsLimit = 100;
}, [](const MTPDstarsTransactionPeerAds &) {
return Data::CreditsHistoryEntry::PeerType::Ads;
}),
- .refunded = tl.data().is_refund(),
- .pending = tl.data().is_pending(),
- .failed = tl.data().is_failed(),
+ .subscriptionUntil = tl.data().vsubscription_period()
+ ? base::unixtime::parse(base::unixtime::now()
+ + tl.data().vsubscription_period()->v)
+ : QDateTime(),
.successDate = tl.data().vtransaction_date()
? base::unixtime::parse(tl.data().vtransaction_date()->v)
: QDateTime(),
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
+ .reaction = tl.data().is_reaction(),
+ .refunded = tl.data().is_refund(),
+ .pending = tl.data().is_pending(),
+ .failed = tl.data().is_failed(),
.in = (int64(tl.data().vstars().v) >= 0),
.gift = tl.data().is_gift(),
};
}
+[[nodiscard]] Data::SubscriptionEntry SubscriptionFromTL(
+ const MTPStarsSubscription &tl) {
+ return Data::SubscriptionEntry{
+ .id = qs(tl.data().vid()),
+ .inviteHash = qs(tl.data().vchat_invite_hash().value_or_empty()),
+ .until = base::unixtime::parse(tl.data().vuntil_date().v),
+ .subscription = Data::PeerSubscription{
+ .credits = tl.data().vpricing().data().vamount().v,
+ .period = tl.data().vpricing().data().vperiod().v,
+ },
+ .barePeerId = peerFromMTP(tl.data().vpeer()).value,
+ .cancelled = tl.data().is_canceled(),
+ .expired = (base::unixtime::now() > tl.data().vuntil_date().v),
+ .canRefulfill = tl.data().is_can_refulfill(),
+ };
+}
+
[[nodiscard]] Data::CreditsStatusSlice StatusFromTL(
const MTPpayments_StarsStatus &status,
not_null peer) {
- peer->owner().processUsers(status.data().vusers());
- peer->owner().processChats(status.data().vchats());
+ const auto &data = status.data();
+ peer->owner().processUsers(data.vusers());
+ peer->owner().processChats(data.vchats());
+ auto entries = std::vector();
+ if (const auto history = data.vhistory()) {
+ entries.reserve(history->v.size());
+ for (const auto &tl : history->v) {
+ entries.push_back(HistoryFromTL(tl, peer));
+ }
+ }
+ auto subscriptions = std::vector();
+ if (const auto history = data.vsubscriptions()) {
+ subscriptions.reserve(history->v.size());
+ for (const auto &tl : history->v) {
+ subscriptions.push_back(SubscriptionFromTL(tl));
+ }
+ }
return Data::CreditsStatusSlice{
- .list = ranges::views::all(
- status.data().vhistory().v
- ) | ranges::views::transform([&](const MTPStarsTransaction &tl) {
- return HistoryFromTL(tl, peer);
- }) | ranges::to_vector,
+ .list = std::move(entries),
+ .subscriptions = std::move(subscriptions),
.balance = status.data().vbalance().v,
+ .subscriptionsMissingBalance
+ = status.data().vsubscriptions_missing_balance().value_or_empty(),
.allLoaded = !status.data().vnext_offset().has_value(),
.token = qs(status.data().vnext_offset().value_or_empty()),
+ .tokenSubscriptions = qs(
+ status.data().vsubscriptions_next_offset().value_or_empty()),
};
}
@@ -195,10 +233,14 @@ void CreditsStatus::request(
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input
)).done([=](const TLResult &result) {
_requestId = 0;
- done(StatusFromTL(result, _peer));
+ if (const auto onstack = done) {
+ onstack(StatusFromTL(result, _peer));
+ }
}).fail([=] {
_requestId = 0;
- done({});
+ if (const auto onstack = done) {
+ onstack({});
+ }
}).send();
}
@@ -220,6 +262,7 @@ void CreditsHistory::request(
}
_requestId = _api.request(MTPpayments_GetStarsTransactions(
MTP_flags(_flags),
+ MTPstring(), // subscription_id
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input,
MTP_string(token),
MTP_int(kTransactionsLimit)
@@ -232,6 +275,25 @@ void CreditsHistory::request(
}).send();
}
+void CreditsHistory::requestSubscriptions(
+ const Data::CreditsStatusSlice::OffsetToken &token,
+ Fn done) {
+ if (_requestId) {
+ return;
+ }
+ _requestId = _api.request(MTPpayments_GetStarsSubscriptions(
+ MTP_flags(0),
+ _peer->isSelf() ? MTP_inputPeerSelf() : _peer->input,
+ MTP_string(token)
+ )).done([=](const MTPpayments_StarsStatus &result) {
+ _requestId = 0;
+ done(StatusFromTL(result, _peer));
+ }).fail([=] {
+ _requestId = 0;
+ done({});
+ }).send();
+}
+
Data::CreditTopupOptions CreditsTopupOptions::options() const {
return _options;
}
diff --git a/Telegram/SourceFiles/api/api_credits.h b/Telegram/SourceFiles/api/api_credits.h
index e63380734..e038d9c95 100644
--- a/Telegram/SourceFiles/api/api_credits.h
+++ b/Telegram/SourceFiles/api/api_credits.h
@@ -60,6 +60,9 @@ public:
void request(
const Data::CreditsStatusSlice::OffsetToken &token,
Fn done);
+ void requestSubscriptions(
+ const Data::CreditsStatusSlice::OffsetToken &token,
+ Fn done);
private:
using HistoryTL = MTPpayments_GetStarsTransactions;
diff --git a/Telegram/SourceFiles/api/api_invite_links.cpp b/Telegram/SourceFiles/api/api_invite_links.cpp
index 1f02b78c1..c89656103 100644
--- a/Telegram/SourceFiles/api/api_invite_links.cpp
+++ b/Telegram/SourceFiles/api/api_invite_links.cpp
@@ -8,12 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_invite_links.h"
#include "api/api_chat_participants.h"
-#include "data/data_peer.h"
-#include "data/data_user.h"
-#include "data/data_chat.h"
-#include "data/data_channel.h"
-#include "data/data_session.h"
#include "data/data_changes.h"
+#include "data/data_channel.h"
+#include "data/data_chat.h"
+#include "data/data_peer.h"
+#include "data/data_session.h"
+#include "data/data_user.h"
#include "main/main_session.h"
#include "base/unixtime.h"
#include "apiwrap.h"
@@ -69,59 +69,46 @@ JoinedByLinkSlice ParseJoinedByLinkSlice(
InviteLinks::InviteLinks(not_null api) : _api(api) {
}
-void InviteLinks::create(
- not_null peer,
- Fn done,
- const QString &label,
- TimeId expireDate,
- int usageLimit,
- bool requestApproval) {
- performCreate(
- peer,
- std::move(done),
- false,
- label,
- expireDate,
- usageLimit,
- requestApproval);
+void InviteLinks::create(const CreateInviteLinkArgs &args) {
+ performCreate(args, false);
}
void InviteLinks::performCreate(
- not_null peer,
- Fn done,
- bool revokeLegacyPermanent,
- const QString &label,
- TimeId expireDate,
- int usageLimit,
- bool requestApproval) {
- if (const auto i = _createCallbacks.find(peer)
+ const CreateInviteLinkArgs &args,
+ bool revokeLegacyPermanent) {
+ if (const auto i = _createCallbacks.find(args.peer)
; i != end(_createCallbacks)) {
- if (done) {
- i->second.push_back(std::move(done));
+ if (args.done) {
+ i->second.push_back(std::move(args.done));
}
return;
}
- auto &callbacks = _createCallbacks[peer];
- if (done) {
- callbacks.push_back(std::move(done));
+ auto &callbacks = _createCallbacks[args.peer];
+ if (args.done) {
+ callbacks.push_back(std::move(args.done));
}
+ const auto requestApproval = !args.subscription && args.requestApproval;
using Flag = MTPmessages_ExportChatInvite::Flag;
_api->request(MTPmessages_ExportChatInvite(
MTP_flags((revokeLegacyPermanent
? Flag::f_legacy_revoke_permanent
: Flag(0))
- | (!label.isEmpty() ? Flag::f_title : Flag(0))
- | (expireDate ? Flag::f_expire_date : Flag(0))
- | ((!requestApproval && usageLimit)
+ | (!args.label.isEmpty() ? Flag::f_title : Flag(0))
+ | (args.expireDate ? Flag::f_expire_date : Flag(0))
+ | ((!requestApproval && args.usageLimit)
? Flag::f_usage_limit
: Flag(0))
- | (requestApproval ? Flag::f_request_needed : Flag(0))),
- peer->input,
- MTP_int(expireDate),
- MTP_int(usageLimit),
- MTP_string(label)
- )).done([=](const MTPExportedChatInvite &result) {
+ | (requestApproval ? Flag::f_request_needed : Flag(0))
+ | (args.subscription ? Flag::f_subscription_pricing : Flag(0))),
+ args.peer->input,
+ MTP_int(args.expireDate),
+ MTP_int(args.usageLimit),
+ MTP_string(args.label),
+ MTP_starsSubscriptionPricing(
+ MTP_int(args.subscription.period),
+ MTP_long(args.subscription.credits))
+ )).done([=, peer = args.peer](const MTPExportedChatInvite &result) {
const auto callbacks = _createCallbacks.take(peer);
const auto link = prepend(peer, peer->session().user(), result);
if (link && callbacks) {
@@ -129,7 +116,7 @@ void InviteLinks::performCreate(
callback(*link);
}
}
- }).fail([=] {
+ }).fail([=, peer = args.peer] {
_createCallbacks.erase(peer);
}).send();
}
@@ -238,6 +225,15 @@ void InviteLinks::edit(
requestApproval);
}
+void InviteLinks::editTitle(
+ not_null peer,
+ not_null admin,
+ const QString &link,
+ const QString &label,
+ Fn done) {
+ performEdit(peer, admin, link, done, false, label, 0, 0, false, true);
+}
+
void InviteLinks::performEdit(
not_null peer,
not_null admin,
@@ -247,7 +243,8 @@ void InviteLinks::performEdit(
const QString &label,
TimeId expireDate,
int usageLimit,
- bool requestApproval) {
+ bool requestApproval,
+ bool editOnlyTitle) {
const auto key = LinkKey{ peer, link };
if (_deleteCallbacks.contains(key)) {
return;
@@ -272,7 +269,7 @@ void InviteLinks::performEdit(
? Flag::f_request_needed
: Flag(0));
_api->request(MTPmessages_EditExportedChatInvite(
- MTP_flags(flags),
+ MTP_flags(editOnlyTitle ? Flag::f_title : flags),
peer->input,
MTP_string(link),
MTP_int(expireDate),
@@ -344,7 +341,7 @@ void InviteLinks::revokePermanent(
} else if (!admin->isSelf()) {
crl::on_main(&peer->session(), done);
} else {
- performCreate(peer, callback, true);
+ performCreate({ peer, callback }, true);
}
}
@@ -750,6 +747,12 @@ auto InviteLinks::parse(
return std::optional(Link{
.link = qs(data.vlink()),
.label = qs(data.vtitle().value_or_empty()),
+ .subscription = data.vsubscription_pricing()
+ ? Data::PeerSubscription{
+ data.vsubscription_pricing()->data().vamount().v,
+ data.vsubscription_pricing()->data().vperiod().v,
+ }
+ : Data::PeerSubscription(),
.admin = peer->session().data().user(data.vadmin_id()),
.date = data.vdate().v,
.startDate = data.vstart_date().value_or_empty(),
diff --git a/Telegram/SourceFiles/api/api_invite_links.h b/Telegram/SourceFiles/api/api_invite_links.h
index 09b43c086..dd52feb99 100644
--- a/Telegram/SourceFiles/api/api_invite_links.h
+++ b/Telegram/SourceFiles/api/api_invite_links.h
@@ -9,11 +9,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class ApiWrap;
+#include "data/data_subscriptions.h"
+
namespace Api {
struct InviteLink {
QString link;
QString label;
+ Data::PeerSubscription subscription;
not_null admin;
TimeId date = 0;
TimeId startDate = 0;
@@ -53,6 +56,16 @@ struct InviteLinkUpdate {
not_null peer,
const MTPmessages_ChatInviteImporters &slice);
+struct CreateInviteLinkArgs {
+ not_null peer;
+ Fn done = nullptr;
+ QString label;
+ TimeId expireDate = 0;
+ int usageLimit = 0;
+ bool requestApproval = false;
+ Data::PeerSubscription subscription;
+};
+
class InviteLinks final {
public:
explicit InviteLinks(not_null api);
@@ -61,13 +74,7 @@ public:
using Links = PeerInviteLinks;
using Update = InviteLinkUpdate;
- void create(
- not_null peer,
- Fn done = nullptr,
- const QString &label = QString(),
- TimeId expireDate = 0,
- int usageLimit = 0,
- bool requestApproval = false);
+ void create(const CreateInviteLinkArgs &args);
void edit(
not_null peer,
not_null admin,
@@ -77,6 +84,12 @@ public:
int usageLimit,
bool requestApproval,
Fn done = nullptr);
+ void editTitle(
+ not_null peer,
+ not_null admin,
+ const QString &link,
+ const QString &label,
+ Fn done = nullptr);
void revoke(
not_null peer,
not_null admin,
@@ -187,15 +200,11 @@ private:
const QString &label = QString(),
TimeId expireDate = 0,
int usageLimit = 0,
- bool requestApproval = false);
+ bool requestApproval = false,
+ bool editOnlyTitle = false);
void performCreate(
- not_null peer,
- Fn done,
- bool revokeLegacyPermanent,
- const QString &label = QString(),
- TimeId expireDate = 0,
- int usageLimit = 0,
- bool requestApproval = false);
+ const CreateInviteLinkArgs &args,
+ bool revokeLegacyPermanent);
void requestJoinedFirstSlice(LinkKey key);
[[nodiscard]] std::optional lookupJoinedFirstSlice(
diff --git a/Telegram/SourceFiles/api/api_premium.cpp b/Telegram/SourceFiles/api/api_premium.cpp
index 6ff4aa130..947b48297 100644
--- a/Telegram/SourceFiles/api/api_premium.cpp
+++ b/Telegram/SourceFiles/api/api_premium.cpp
@@ -39,9 +39,9 @@ namespace {
};
}
-[[nodiscard]] Data::SubscriptionOptions GiftCodesFromTL(
+[[nodiscard]] Data::PremiumSubscriptionOptions GiftCodesFromTL(
const QVector &tlOptions) {
- auto options = SubscriptionOptionsFromTL(tlOptions);
+ auto options = PremiumSubscriptionOptionsFromTL(tlOptions);
for (auto i = 0; i < options.size(); i++) {
const auto &tlOption = tlOptions[i].data();
const auto perUserText = Ui::FillAmountAndCurrency(
@@ -143,7 +143,7 @@ void Premium::reloadPromo() {
const auto &data = result.data();
_session->data().processUsers(data.vusers());
- _subscriptionOptions = SubscriptionOptionsFromTL(
+ _subscriptionOptions = PremiumSubscriptionOptionsFromTL(
data.vperiod_options().v);
for (const auto &option : data.vperiod_options().v) {
if (option.data().vmonths().v == 1) {
@@ -372,7 +372,7 @@ void Premium::resolveGiveawayInfo(
}).send();
}
-const Data::SubscriptionOptions &Premium::subscriptionOptions() const {
+const Data::PremiumSubscriptionOptions &Premium::subscriptionOptions() const {
return _subscriptionOptions;
}
@@ -547,7 +547,7 @@ Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice(
};
}
-Data::SubscriptionOptions PremiumGiftCodeOptions::options(int amount) {
+Data::PremiumSubscriptionOptions PremiumGiftCodeOptions::options(int amount) {
const auto it = _subscriptionOptions.find(amount);
if (it != end(_subscriptionOptions)) {
return it->second;
diff --git a/Telegram/SourceFiles/api/api_premium.h b/Telegram/SourceFiles/api/api_premium.h
index 83423fcd2..e05ddfaf7 100644
--- a/Telegram/SourceFiles/api/api_premium.h
+++ b/Telegram/SourceFiles/api/api_premium.h
@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
-#include "data/data_subscription_option.h"
+#include "data/data_premium_subscription_option.h"
#include "mtproto/sender.h"
class History;
@@ -106,7 +106,7 @@ public:
Fn done);
[[nodiscard]] auto subscriptionOptions() const
- -> const Data::SubscriptionOptions &;
+ -> const Data::PremiumSubscriptionOptions &;
[[nodiscard]] rpl::producer<> somePremiumRequiredResolved() const;
void resolvePremiumRequired(not_null user);
@@ -156,7 +156,7 @@ private:
MsgId _giveawayInfoMessageId = 0;
Fn _giveawayInfoDone;
- Data::SubscriptionOptions _subscriptionOptions;
+ Data::PremiumSubscriptionOptions _subscriptionOptions;
rpl::event_stream<> _somePremiumRequiredResolved;
base::flat_set> _resolvePremiumRequiredUsers;
@@ -170,7 +170,7 @@ public:
PremiumGiftCodeOptions(not_null peer);
[[nodiscard]] rpl::producer request();
- [[nodiscard]] Data::SubscriptionOptions options(int amount);
+ [[nodiscard]] Data::PremiumSubscriptionOptions options(int amount);
[[nodiscard]] const std::vector &availablePresets() const;
[[nodiscard]] int monthsFromPreset(int monthsIndex);
[[nodiscard]] Payments::InvoicePremiumGiftCode invoice(
@@ -200,8 +200,9 @@ private:
int quantity = 0;
};
using Amount = int;
+ using PremiumSubscriptionOptions = Data::PremiumSubscriptionOptions;
const not_null _peer;
- base::flat_map _subscriptionOptions;
+ base::flat_map _subscriptionOptions;
struct {
std::vector months;
std::vector totalCosts;
diff --git a/Telegram/SourceFiles/api/api_premium_option.cpp b/Telegram/SourceFiles/api/api_premium_option.cpp
index 135082e94..bd3056a75 100644
--- a/Telegram/SourceFiles/api/api_premium_option.cpp
+++ b/Telegram/SourceFiles/api/api_premium_option.cpp
@@ -13,7 +13,7 @@ namespace Api {
constexpr auto kDiscountDivider = 1.;
-Data::SubscriptionOption CreateSubscriptionOption(
+Data::PremiumSubscriptionOption CreateSubscriptionOption(
int months,
int monthlyAmount,
int64 amount,
diff --git a/Telegram/SourceFiles/api/api_premium_option.h b/Telegram/SourceFiles/api/api_premium_option.h
index 5758a8cb8..afe66ac4a 100644
--- a/Telegram/SourceFiles/api/api_premium_option.h
+++ b/Telegram/SourceFiles/api/api_premium_option.h
@@ -7,11 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
-#include "data/data_subscription_option.h"
+#include "data/data_premium_subscription_option.h"
namespace Api {
-[[nodiscard]] Data::SubscriptionOption CreateSubscriptionOption(
+[[nodiscard]] Data::PremiumSubscriptionOption CreateSubscriptionOption(
int months,
int monthlyAmount,
int64 amount,
@@ -19,22 +19,22 @@ namespace Api {
const QString &botUrl);
template
-[[nodiscard]] Data::SubscriptionOptions SubscriptionOptionsFromTL(
- const QVector