payments_edit_information.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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 "payments/ui/payments_edit_information.h"
  8. #include "payments/ui/payments_panel_delegate.h"
  9. #include "payments/ui/payments_field.h"
  10. #include "ui/widgets/scroll_area.h"
  11. #include "ui/widgets/buttons.h"
  12. #include "ui/widgets/labels.h"
  13. #include "ui/widgets/checkbox.h"
  14. #include "ui/wrap/vertical_layout.h"
  15. #include "ui/wrap/fade_wrap.h"
  16. #include "lang/lang_keys.h"
  17. #include "styles/style_payments.h"
  18. #include "styles/style_passport.h"
  19. namespace Payments::Ui {
  20. namespace {
  21. constexpr auto kMaxStreetSize = 64;
  22. constexpr auto kMaxPostcodeSize = 10;
  23. constexpr auto kMaxNameSize = 64;
  24. constexpr auto kMaxEmailSize = 128;
  25. constexpr auto kMaxPhoneSize = 16;
  26. constexpr auto kMinCitySize = 2;
  27. constexpr auto kMaxCitySize = 64;
  28. } // namespace
  29. EditInformation::EditInformation(
  30. QWidget *parent,
  31. const Invoice &invoice,
  32. const RequestedInformation &current,
  33. InformationField field,
  34. not_null<PanelDelegate*> delegate)
  35. : _delegate(delegate)
  36. , _invoice(invoice)
  37. , _information(current)
  38. , _scroll(this, st::passportPanelScroll)
  39. , _topShadow(this)
  40. , _bottomShadow(this)
  41. , _submit(
  42. this,
  43. tr::lng_settings_save(),
  44. st::paymentsPanelButton)
  45. , _cancel(
  46. this,
  47. tr::lng_cancel(),
  48. st::paymentsPanelButton) {
  49. setupControls();
  50. }
  51. EditInformation::~EditInformation() = default;
  52. void EditInformation::setFocus(InformationField field) {
  53. _focusField = field;
  54. if (const auto control = lookupField(field)) {
  55. _scroll->ensureWidgetVisible(control->widget());
  56. control->setFocus();
  57. }
  58. }
  59. void EditInformation::setFocusFast(InformationField field) {
  60. _focusField = field;
  61. if (const auto control = lookupField(field)) {
  62. _scroll->ensureWidgetVisible(control->widget());
  63. control->setFocusFast();
  64. }
  65. }
  66. void EditInformation::showError(InformationField field) {
  67. if (const auto control = lookupField(field)) {
  68. _scroll->ensureWidgetVisible(control->widget());
  69. control->showError();
  70. }
  71. }
  72. void EditInformation::setupControls() {
  73. const auto inner = setupContent();
  74. _submit->addClickHandler([=] {
  75. _delegate->panelValidateInformation(collect());
  76. });
  77. _cancel->addClickHandler([=] {
  78. _delegate->panelCancelEdit();
  79. });
  80. using namespace rpl::mappers;
  81. _topShadow->toggleOn(
  82. _scroll->scrollTopValue() | rpl::map(_1 > 0));
  83. _bottomShadow->toggleOn(rpl::combine(
  84. _scroll->scrollTopValue(),
  85. _scroll->heightValue(),
  86. inner->heightValue(),
  87. _1 + _2 < _3));
  88. }
  89. not_null<RpWidget*> EditInformation::setupContent() {
  90. const auto inner = _scroll->setOwnedWidget(
  91. object_ptr<VerticalLayout>(this));
  92. _scroll->widthValue(
  93. ) | rpl::start_with_next([=](int width) {
  94. inner->resizeToWidth(width);
  95. }, inner->lifetime());
  96. const auto showBox = [=](object_ptr<BoxContent> box) {
  97. _delegate->panelShowBox(std::move(box));
  98. };
  99. auto last = (Field*)nullptr;
  100. const auto add = [&](FieldConfig &&config) {
  101. auto result = std::make_unique<Field>(inner, std::move(config));
  102. inner->add(result->ownedWidget(), st::paymentsFieldPadding);
  103. if (last) {
  104. last->setNextField(result.get());
  105. result->setPreviousField(last);
  106. }
  107. last = result.get();
  108. return result;
  109. };
  110. if (_invoice.isShippingAddressRequested) {
  111. _street1 = add({
  112. .placeholder = tr::lng_payments_address_street1(),
  113. .value = _information.shippingAddress.address1,
  114. .validator = RangeLengthValidator(1, kMaxStreetSize),
  115. });
  116. _street2 = add({
  117. .placeholder = tr::lng_payments_address_street2(),
  118. .value = _information.shippingAddress.address2,
  119. .validator = MaxLengthValidator(kMaxStreetSize),
  120. });
  121. _city = add({
  122. .placeholder = tr::lng_payments_address_city(),
  123. .value = _information.shippingAddress.city,
  124. .validator = RangeLengthValidator(kMinCitySize, kMaxCitySize),
  125. });
  126. _state = add({
  127. .placeholder = tr::lng_payments_address_state(),
  128. .value = _information.shippingAddress.state,
  129. });
  130. _country = add({
  131. .type = FieldType::Country,
  132. .placeholder = tr::lng_payments_address_country(),
  133. .value = _information.shippingAddress.countryIso2,
  134. .validator = RequiredFinishedValidator(),
  135. .showBox = showBox,
  136. .defaultCountry = _information.defaultCountry,
  137. });
  138. _postcode = add({
  139. .placeholder = tr::lng_payments_address_postcode(),
  140. .value = _information.shippingAddress.postcode,
  141. .validator = RangeLengthValidator(1, kMaxPostcodeSize),
  142. });
  143. }
  144. if (_invoice.isNameRequested) {
  145. _name = add({
  146. .placeholder = tr::lng_payments_info_name(),
  147. .value = _information.name,
  148. .validator = RangeLengthValidator(1, kMaxNameSize),
  149. });
  150. }
  151. if (_invoice.isEmailRequested) {
  152. _email = add({
  153. .type = FieldType::Email,
  154. .placeholder = tr::lng_payments_info_email(),
  155. .value = _information.email,
  156. .validator = RangeLengthValidator(1, kMaxEmailSize),
  157. });
  158. }
  159. if (_invoice.isPhoneRequested) {
  160. _phone = add({
  161. .type = FieldType::Phone,
  162. .placeholder = tr::lng_payments_info_phone(),
  163. .value = _information.phone,
  164. .validator = RangeLengthValidator(1, kMaxPhoneSize),
  165. .defaultPhone = _information.defaultPhone,
  166. });
  167. }
  168. const auto emailToProvider = _invoice.isEmailRequested
  169. && _invoice.emailSentToProvider;
  170. const auto phoneToProvider = _invoice.isPhoneRequested
  171. && _invoice.phoneSentToProvider;
  172. if (emailToProvider || phoneToProvider) {
  173. inner->add(
  174. object_ptr<Ui::FlatLabel>(
  175. inner,
  176. ((emailToProvider && phoneToProvider)
  177. ? tr::lng_payments_to_provider_phone_email
  178. : emailToProvider
  179. ? tr::lng_payments_to_provider_email
  180. : tr::lng_payments_to_provider_phone)(
  181. lt_provider,
  182. rpl::single(_invoice.provider)),
  183. st::paymentsToProviderLabel),
  184. st::paymentsToProviderPadding);
  185. }
  186. _save = inner->add(
  187. object_ptr<Ui::Checkbox>(
  188. inner,
  189. tr::lng_payments_save_information(tr::now),
  190. true),
  191. st::paymentsSaveCheckboxPadding);
  192. if (last) {
  193. last->submitted(
  194. ) | rpl::start_with_next([=] {
  195. _delegate->panelValidateInformation(collect());
  196. }, lifetime());
  197. }
  198. return inner;
  199. }
  200. void EditInformation::resizeEvent(QResizeEvent *e) {
  201. updateControlsGeometry();
  202. }
  203. void EditInformation::focusInEvent(QFocusEvent *e) {
  204. if (const auto control = lookupField(_focusField)) {
  205. control->setFocus();
  206. }
  207. }
  208. void EditInformation::updateControlsGeometry() {
  209. const auto &padding = st::paymentsPanelPadding;
  210. const auto buttonsHeight = padding.top()
  211. + _cancel->height()
  212. + padding.bottom();
  213. const auto buttonsTop = height() - buttonsHeight;
  214. _scroll->setGeometry(0, 0, width(), buttonsTop);
  215. _topShadow->resizeToWidth(width());
  216. _topShadow->moveToLeft(0, 0);
  217. _bottomShadow->resizeToWidth(width());
  218. _bottomShadow->moveToLeft(0, buttonsTop - st::lineWidth);
  219. auto right = padding.right();
  220. _submit->moveToRight(right, buttonsTop + padding.top());
  221. right += _submit->width() + padding.left();
  222. _cancel->moveToRight(right, buttonsTop + padding.top());
  223. _scroll->updateBars();
  224. }
  225. auto EditInformation::lookupField(InformationField field) const -> Field* {
  226. switch (field) {
  227. case InformationField::ShippingStreet: return _street1.get();
  228. case InformationField::ShippingCity: return _city.get();
  229. case InformationField::ShippingState: return _state.get();
  230. case InformationField::ShippingCountry: return _country.get();
  231. case InformationField::ShippingPostcode: return _postcode.get();
  232. case InformationField::Name: return _name.get();
  233. case InformationField::Email: return _email.get();
  234. case InformationField::Phone: return _phone.get();
  235. }
  236. Unexpected("Unknown field in EditInformation::lookupField.");
  237. }
  238. RequestedInformation EditInformation::collect() const {
  239. return {
  240. .defaultPhone = _information.defaultPhone,
  241. .defaultCountry = _information.defaultCountry,
  242. .save = _save->checked(),
  243. .name = _name ? _name->value() : QString(),
  244. .phone = _phone ? _phone->value() : QString(),
  245. .email = _email ? _email->value() : QString(),
  246. .shippingAddress = {
  247. .address1 = _street1 ? _street1->value() : QString(),
  248. .address2 = _street2 ? _street2->value() : QString(),
  249. .city = _city ? _city->value() : QString(),
  250. .state = _state ? _state->value() : QString(),
  251. .countryIso2 = _country ? _country->value() : QString(),
  252. .postcode = _postcode ? _postcode->value() : QString(),
  253. },
  254. };
  255. }
  256. } // namespace Payments::Ui