sent_code_field.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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 "ui/widgets/sent_code_field.h"
  8. #include "lang/lang_keys.h"
  9. #include <QRegularExpression>
  10. namespace Ui {
  11. SentCodeField::SentCodeField(
  12. QWidget *parent,
  13. const style::InputField &st,
  14. rpl::producer<QString> placeholder,
  15. const QString &val)
  16. : Ui::InputField(parent, st, std::move(placeholder), val) {
  17. changes() | rpl::start_with_next([=] { fix(); }, lifetime());
  18. }
  19. void SentCodeField::setAutoSubmit(int length, Fn<void()> submitCallback) {
  20. _autoSubmitLength = length;
  21. _submitCallback = std::move(submitCallback);
  22. }
  23. void SentCodeField::setChangedCallback(Fn<void()> changedCallback) {
  24. _changedCallback = std::move(changedCallback);
  25. }
  26. QString SentCodeField::getDigitsOnly() const {
  27. return QString(
  28. getLastText()
  29. ).remove(TextUtilities::RegExpDigitsExclude());
  30. }
  31. void SentCodeField::fix() {
  32. if (_fixing) return;
  33. _fixing = true;
  34. auto newText = QString();
  35. const auto now = getLastText();
  36. auto oldPos = textCursor().position();
  37. auto newPos = -1;
  38. auto oldLen = now.size();
  39. auto digitCount = 0;
  40. for (const auto &ch : now) {
  41. if (ch.isDigit()) {
  42. ++digitCount;
  43. }
  44. }
  45. if (_autoSubmitLength > 0 && digitCount > _autoSubmitLength) {
  46. digitCount = _autoSubmitLength;
  47. }
  48. const auto strict = (_autoSubmitLength > 0)
  49. && (digitCount == _autoSubmitLength);
  50. newText.reserve(oldLen);
  51. int i = 0;
  52. for (const auto &ch : now) {
  53. if (i++ == oldPos) {
  54. newPos = newText.length();
  55. }
  56. if (ch.isDigit()) {
  57. if (!digitCount--) {
  58. break;
  59. }
  60. newText += ch;
  61. if (strict && !digitCount) {
  62. break;
  63. }
  64. } else if (ch == '-') {
  65. newText += ch;
  66. }
  67. }
  68. if (newPos < 0) {
  69. newPos = newText.length();
  70. }
  71. if (newText != now) {
  72. setText(newText);
  73. setCursorPosition(newPos);
  74. }
  75. _fixing = false;
  76. if (_changedCallback) {
  77. _changedCallback();
  78. }
  79. if (strict && _submitCallback) {
  80. _submitCallback();
  81. }
  82. }
  83. SentCodeCall::SentCodeCall(
  84. FnMut<void()> callCallback,
  85. Fn<void()> updateCallback)
  86. : _call(std::move(callCallback))
  87. , _update(std::move(updateCallback)) {
  88. _timer.setCallback([=] {
  89. if (_status.state == State::Waiting) {
  90. if (--_status.timeout <= 0) {
  91. _status.state = State::Calling;
  92. _timer.cancel();
  93. if (_call) {
  94. _call();
  95. }
  96. }
  97. }
  98. if (_update) {
  99. _update();
  100. }
  101. });
  102. }
  103. void SentCodeCall::setStatus(const Status &status) {
  104. _status = status;
  105. if (_status.state == State::Waiting) {
  106. _timer.callEach(1000);
  107. }
  108. }
  109. QString SentCodeCall::getText() const {
  110. switch (_status.state) {
  111. case State::Waiting: {
  112. if (_status.timeout >= 3600) {
  113. return tr::lng_code_call(
  114. tr::now,
  115. lt_minutes,
  116. (u"%1:%2"_q)
  117. .arg(_status.timeout / 3600)
  118. .arg((_status.timeout / 60) % 60, 2, 10, QChar('0')),
  119. lt_seconds,
  120. (u"%1"_q).arg(_status.timeout % 60, 2, 10, QChar('0')));
  121. }
  122. return tr::lng_code_call(
  123. tr::now,
  124. lt_minutes,
  125. QString::number(_status.timeout / 60),
  126. lt_seconds,
  127. (u"%1"_q).arg(_status.timeout % 60, 2, 10, QChar('0')));
  128. } break;
  129. case State::Calling: return tr::lng_code_calling(tr::now);
  130. case State::Called: return tr::lng_code_called(tr::now);
  131. }
  132. return QString();
  133. }
  134. void SentCodeCall::callDone() {
  135. if (_status.state == State::Calling) {
  136. _status.state = State::Called;
  137. if (_update) {
  138. _update();
  139. }
  140. }
  141. }
  142. } // namespace Ui