self_destruction_box.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "boxes/self_destruction_box.h"
  8. #include "api/api_authorizations.h"
  9. #include "api/api_cloud_password.h"
  10. #include "api/api_self_destruct.h"
  11. #include "apiwrap.h"
  12. #include "boxes/passcode_box.h"
  13. #include "lang/lang_keys.h"
  14. #include "main/main_session.h"
  15. #include "ui/widgets/checkbox.h"
  16. #include "ui/widgets/labels.h"
  17. #include "ui/text/text_utilities.h"
  18. #include "ui/widgets/menu/menu_add_action_callback.h"
  19. #include "ui/widgets/menu/menu_add_action_callback_factory.h"
  20. #include "ui/widgets/popup_menu.h"
  21. #include "styles/style_boxes.h"
  22. #include "styles/style_info.h"
  23. #include "styles/style_layers.h"
  24. #include "styles/style_menu_icons.h"
  25. #include "styles/style_widgets.h"
  26. namespace {
  27. using Type = SelfDestructionBox::Type;
  28. void AddDeleteAccount(
  29. not_null<Ui::BoxContent*> box,
  30. not_null<Main::Session*> session) {
  31. if (!session->isTestMode()) {
  32. return;
  33. }
  34. const auto maybeState = session->api().cloudPassword().stateCurrent();
  35. if (!maybeState || !maybeState->hasPassword) {
  36. return;
  37. }
  38. const auto top = box->addTopButton(st::infoTopBarMenu);
  39. const auto menu
  40. = top->lifetime().make_state<base::unique_qptr<Ui::PopupMenu>>();
  41. const auto handler = [=] {
  42. session->api().cloudPassword().state(
  43. ) | rpl::take(
  44. 1
  45. ) | rpl::start_with_next([=](const Core::CloudPasswordState &state) {
  46. auto fields = PasscodeBox::CloudFields::From(state);
  47. fields.customTitle = tr::lng_settings_destroy_title();
  48. fields.customDescription = tr::lng_context_mark_read_all_sure_2(
  49. tr::now,
  50. Ui::Text::RichLangValue).text;
  51. fields.customSubmitButton = tr::lng_theme_delete();
  52. fields.customCheckCallback = [=](
  53. const Core::CloudPasswordResult &result,
  54. QPointer<PasscodeBox> box) {
  55. session->api().request(MTPaccount_DeleteAccount(
  56. MTP_flags(MTPaccount_DeleteAccount::Flag::f_password),
  57. MTP_string("Manual"),
  58. result.result
  59. )).done([=] {
  60. if (box) {
  61. box->uiShow()->hideLayer();
  62. }
  63. }).fail([=](const MTP::Error &error) {
  64. if (box) {
  65. box->handleCustomCheckError(error.type());
  66. }
  67. }).send();
  68. };
  69. box->uiShow()->showBox(Box<PasscodeBox>(session, fields));
  70. }, top->lifetime());
  71. };
  72. top->setClickedCallback([=] {
  73. *menu = base::make_unique_q<Ui::PopupMenu>(
  74. top,
  75. st::popupMenuWithIcons);
  76. const auto addAction = Ui::Menu::CreateAddActionCallback(menu->get());
  77. addAction({
  78. .text = tr::lng_settings_destroy_title(tr::now),
  79. .handler = handler,
  80. .icon = &st::menuIconDeleteAttention,
  81. .isAttention = true,
  82. });
  83. (*menu)->popup(QCursor::pos());
  84. });
  85. }
  86. [[nodiscard]] std::vector<int> Values(Type type) {
  87. switch (type) {
  88. case Type::Account: return { 30, 90, 180, 365, 548, 720 };
  89. case Type::Sessions: return { 7, 30, 90, 180, 365 };
  90. }
  91. Unexpected("SelfDestructionBox::Type in Values.");
  92. }
  93. } // namespace
  94. SelfDestructionBox::SelfDestructionBox(
  95. QWidget*,
  96. not_null<Main::Session*> session,
  97. Type type,
  98. rpl::producer<int> preloaded)
  99. : _type(type)
  100. , _session(session)
  101. , _ttlValues(Values(type))
  102. , _loading(
  103. this,
  104. tr::lng_contacts_loading(tr::now),
  105. st::membersAbout) {
  106. std::move(
  107. preloaded
  108. ) | rpl::take(
  109. 1
  110. ) | rpl::start_with_next([=](int days) {
  111. gotCurrent(days);
  112. }, lifetime());
  113. }
  114. void SelfDestructionBox::gotCurrent(int days) {
  115. Expects(!_ttlValues.empty());
  116. _loading.destroy();
  117. auto daysAdjusted = _ttlValues[0];
  118. for (const auto value : _ttlValues) {
  119. if (qAbs(days - value) < qAbs(days - daysAdjusted)) {
  120. daysAdjusted = value;
  121. }
  122. }
  123. _ttlGroup = std::make_shared<Ui::RadiobuttonGroup>(daysAdjusted);
  124. if (_prepared) {
  125. showContent();
  126. }
  127. }
  128. void SelfDestructionBox::showContent() {
  129. auto y = st::boxOptionListPadding.top();
  130. _description.create(
  131. this,
  132. (_type == Type::Account
  133. ? tr::lng_self_destruct_description(tr::now)
  134. : tr::lng_self_destruct_sessions_description(tr::now)),
  135. st::boxLabel);
  136. _description->moveToLeft(st::boxPadding.left(), y);
  137. y += _description->height() + st::boxMediumSkip;
  138. for (const auto value : _ttlValues) {
  139. const auto button = Ui::CreateChild<Ui::Radiobutton>(
  140. this,
  141. _ttlGroup,
  142. value,
  143. DaysLabel(value),
  144. st::autolockButton);
  145. button->moveToLeft(st::boxPadding.left(), y);
  146. y += button->heightNoMargins() + st::boxOptionListSkip;
  147. }
  148. showChildren();
  149. clearButtons();
  150. addButton(tr::lng_settings_save(), [=] {
  151. const auto value = _ttlGroup->current();
  152. switch (_type) {
  153. case Type::Account:
  154. _session->api().selfDestruct().updateAccountTTL(value);
  155. break;
  156. case Type::Sessions:
  157. _session->api().authorizations().updateTTL(value);
  158. break;
  159. }
  160. closeBox();
  161. });
  162. addButton(tr::lng_cancel(), [=] { closeBox(); });
  163. }
  164. QString SelfDestructionBox::DaysLabel(int days) {
  165. return !days
  166. ? QString()
  167. //: (days > 364)
  168. //? tr::lng_years(tr::now, lt_count, days / 365)
  169. : (days > 25)
  170. ? tr::lng_months(tr::now, lt_count, std::max(days / 30, 1))
  171. : tr::lng_weeks(tr::now, lt_count, std::max(days / 7, 1));
  172. }
  173. void SelfDestructionBox::prepare() {
  174. setTitle((_type == Type::Account
  175. ? tr::lng_self_destruct_title()
  176. : tr::lng_self_destruct_sessions_title()));
  177. auto fake = object_ptr<Ui::FlatLabel>(
  178. this,
  179. (_type == Type::Account
  180. ? tr::lng_self_destruct_description(tr::now)
  181. : tr::lng_self_destruct_sessions_description(tr::now)),
  182. st::boxLabel);
  183. const auto boxHeight = st::boxOptionListPadding.top()
  184. + fake->height() + st::boxMediumSkip
  185. + (_ttlValues.size()
  186. * (st::defaultRadio.diameter + st::boxOptionListSkip))
  187. - st::boxOptionListSkip
  188. + st::boxOptionListPadding.bottom() + st::boxPadding.bottom();
  189. fake.destroy();
  190. setDimensions(st::boxWidth, boxHeight);
  191. addButton(tr::lng_cancel(), [this] { closeBox(); });
  192. if (_loading) {
  193. _loading->moveToLeft(
  194. (st::boxWidth - _loading->width()) / 2,
  195. boxHeight / 3);
  196. _prepared = true;
  197. } else {
  198. showContent();
  199. }
  200. AddDeleteAccount(this, _session);
  201. }