Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef5e39f680 | ||
|
|
27228480a8 | ||
|
|
eebe1f4c11 | ||
|
|
5d5e4cbdff | ||
|
|
7e9920b5ea | ||
|
|
297fd0f0c8 | ||
|
|
0eec470387 | ||
|
|
7a64725045 | ||
|
|
1acfe441e1 | ||
|
|
80e932a083 | ||
|
|
698d32db57 | ||
|
|
2ee7cc784f | ||
|
|
071411c8b9 | ||
|
|
43671e2b47 | ||
|
|
1666683dbb | ||
|
|
c134861cd9 | ||
|
|
a1a5ef9d39 | ||
|
|
7e98e9ecf2 | ||
|
|
cad6faa790 | ||
|
|
13ad39dfc2 | ||
|
|
aa8ca28f77 | ||
|
|
d424a8b039 | ||
|
|
9896855789 | ||
|
|
613d4932ca | ||
|
|
44f79b8331 | ||
|
|
aa1117a714 | ||
|
|
8748265b00 | ||
|
|
be8aeb0d96 | ||
|
|
599cc35e57 | ||
|
|
bd367da1bd | ||
|
|
62b50a41c8 | ||
|
|
a3caecbc07 | ||
|
|
71354d1611 |
@@ -849,6 +849,8 @@ PRIVATE
|
||||
info/profile/info_profile_members.h
|
||||
info/profile/info_profile_members_controllers.cpp
|
||||
info/profile/info_profile_members_controllers.h
|
||||
info/profile/info_profile_phone_menu.cpp
|
||||
info/profile/info_profile_phone_menu.h
|
||||
info/profile/info_profile_text.cpp
|
||||
info/profile/info_profile_text.h
|
||||
info/profile/info_profile_values.cpp
|
||||
|
||||
BIN
Telegram/Resources/icons/fragment.png
Normal file
BIN
Telegram/Resources/icons/fragment.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 525 B |
BIN
Telegram/Resources/icons/fragment@2x.png
Normal file
BIN
Telegram/Resources/icons/fragment@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Telegram/Resources/icons/fragment@3x.png
Normal file
BIN
Telegram/Resources/icons/fragment@3x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -323,6 +323,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_intro_qr_step3" = "Scan this image to Log In";
|
||||
"lng_intro_qr_skip" = "Or log in using your phone number";
|
||||
|
||||
"lng_intro_fragment_title" = "Enter code";
|
||||
"lng_intro_fragment_about" = "Get the code for {phone_number} in the Anonymous Numbers section on Fragment.";
|
||||
"lng_intro_fragment_button" = "Open Fragment";
|
||||
|
||||
"lng_phone_title" = "Your Phone Number";
|
||||
"lng_phone_desc" = "Please confirm your country code and\nenter your mobile phone number.";
|
||||
"lng_phone_to_qr" = "Quick log in using QR code";
|
||||
@@ -751,6 +755,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_download_path" = "Download path";
|
||||
"lng_download_path_temp" = "Temp folder";
|
||||
"lng_download_path_default" = "Default folder";
|
||||
"lng_download_path_unset" = "Unset";
|
||||
"lng_download_path_clear" = "Clear all";
|
||||
"lng_download_path_header" = "Choose download path";
|
||||
"lng_download_path_default_radio" = "Telegram folder in system «Downloads»";
|
||||
@@ -1192,6 +1197,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_info_tab_media" = "Media";
|
||||
"lng_info_public_photo" = "public photo";
|
||||
"lng_info_mobile_label" = "Mobile";
|
||||
"lng_info_mobile_context_menu_fragment_about" = "This number is not tied to a SIM card and was acquired on {link}.";
|
||||
"lng_info_mobile_context_menu_fragment_about_link" = "Fragment";
|
||||
"lng_info_mobile_hidden" = "Hidden";
|
||||
"lng_info_username_label" = "Username";
|
||||
"lng_info_usernames_label" = "also";
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="4.4.2.0" />
|
||||
Version="4.4.3.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,4,2,0
|
||||
PRODUCTVERSION 4,4,2,0
|
||||
FILEVERSION 4,4,3,0
|
||||
PRODUCTVERSION 4,4,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "4.4.2.0"
|
||||
VALUE "FileVersion", "4.4.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "4.4.2.0"
|
||||
VALUE "ProductVersion", "4.4.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,4,2,0
|
||||
PRODUCTVERSION 4,4,2,0
|
||||
FILEVERSION 4,4,3,0
|
||||
PRODUCTVERSION 4,4,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "4.4.2.0"
|
||||
VALUE "FileVersion", "4.4.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "4.4.2.0"
|
||||
VALUE "ProductVersion", "4.4.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_phone_box.h"
|
||||
@@ -58,6 +59,10 @@ void ConfirmPhone::resolve(
|
||||
}, [&](const MTPDauth_sentCodeTypeSetUpEmailRequired &) {
|
||||
return bad("SetUpEmailRequired");
|
||||
});
|
||||
const auto fragmentUrl = data.vtype().match([](
|
||||
const MTPDauth_sentCodeTypeFragmentSms &data) {
|
||||
return qs(data.vurl());
|
||||
}, [](const auto &) { return QString(); });
|
||||
const auto phoneHash = qs(data.vphone_code_hash());
|
||||
const auto timeout = [&]() -> std::optional<int> {
|
||||
if (const auto nextType = data.vnext_type()) {
|
||||
@@ -70,8 +75,15 @@ void ConfirmPhone::resolve(
|
||||
auto box = Box<Ui::ConfirmPhoneBox>(
|
||||
phone,
|
||||
sentCodeLength,
|
||||
fragmentUrl,
|
||||
timeout);
|
||||
const auto boxWeak = Ui::MakeWeak(box.data());
|
||||
using LoginCode = rpl::event_stream<QString>;
|
||||
const auto codeHandles = box->lifetime().make_state<LoginCode>();
|
||||
controller->session().account().setHandleLoginCode([=](
|
||||
const QString &code) {
|
||||
codeHandles->fire_copy(code);
|
||||
});
|
||||
box->resendRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
_api.request(MTPauth_ResendCode(
|
||||
@@ -83,7 +95,9 @@ void ConfirmPhone::resolve(
|
||||
}
|
||||
}).send();
|
||||
}, box->lifetime());
|
||||
box->checkRequests(
|
||||
rpl::merge(
|
||||
codeHandles->events(),
|
||||
box->checkRequests()
|
||||
) | rpl::start_with_next([=](const QString &code) {
|
||||
if (_checkRequestId) {
|
||||
return;
|
||||
@@ -115,6 +129,10 @@ void ConfirmPhone::resolve(
|
||||
boxWeak->showServerError(errorText);
|
||||
}).handleFloodErrors().send();
|
||||
}, box->lifetime());
|
||||
box->boxClosing(
|
||||
) | rpl::start_with_next([=] {
|
||||
controller->session().account().setHandleLoginCode(nullptr);
|
||||
}, box->lifetime());
|
||||
|
||||
controller->show(std::move(box), Ui::LayerOption::CloseOther);
|
||||
});
|
||||
|
||||
@@ -467,6 +467,7 @@ void GroupInfoBox::prepare() {
|
||||
&_navigation->parentController()->window(),
|
||||
Ui::UserpicButton::Role::ChoosePhoto,
|
||||
st::defaultUserpicButton);
|
||||
_photo->showCustomOnChosen();
|
||||
_title.create(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
@@ -640,10 +641,11 @@ void GroupInfoBox::createGroup(
|
||||
MTP_int(_ttlPeriod)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
auto image = _photo->takeResultImage();
|
||||
const auto period = _ttlPeriod;
|
||||
const auto navigation = _navigation;
|
||||
|
||||
getDelegate()->hideLayer(); // Destroys 'this'.
|
||||
ChatCreateDone(navigation, std::move(image), _ttlPeriod, result);
|
||||
ChatCreateDone(navigation, std::move(image), period, result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
const auto &type = error.type();
|
||||
_creationRequestId = 0;
|
||||
|
||||
@@ -293,6 +293,10 @@ membersAbout: FlatLabel(defaultFlatLabel) {
|
||||
style: boxLabelStyle;
|
||||
}
|
||||
|
||||
fragmentBoxButton: RoundButton(introFragmentButton) {
|
||||
width: 256px;
|
||||
}
|
||||
|
||||
passcodeHeaderFont: font(19px);
|
||||
passcodeHeaderHeight: 80px;
|
||||
passcodeInput: InputField(introPhone) {
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/change_phone_box.h"
|
||||
|
||||
#include "core/file_utilities.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/sent_code_field.h"
|
||||
@@ -19,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/phone_banned_box.h"
|
||||
#include "countries/countries_instance.h" // Countries::ExtractPhoneCode.
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
@@ -67,6 +69,10 @@ void CreateErrorLabel(
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] int ErrorSkip() {
|
||||
return st::boxLittleSkip + st::changePhoneError.style.font->height;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Settings {
|
||||
@@ -109,6 +115,7 @@ public:
|
||||
not_null<Window::SessionController*> controller,
|
||||
const QString &phone,
|
||||
const QString &hash,
|
||||
const QString &openUrl,
|
||||
int codeLength,
|
||||
int callTimeout);
|
||||
|
||||
@@ -120,7 +127,7 @@ protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
void submit();
|
||||
void submit(const QString &code);
|
||||
void sendCall();
|
||||
void updateCall();
|
||||
void sendCodeFail(const MTP::Error &error);
|
||||
@@ -128,18 +135,20 @@ private:
|
||||
void hideError() {
|
||||
showError(QString());
|
||||
}
|
||||
int countHeight();
|
||||
[[nodiscard]] int countHeight() const;
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
MTP::Sender _api;
|
||||
|
||||
QString _phone;
|
||||
QString _hash;
|
||||
QString _openUrl;
|
||||
int _codeLength = 0;
|
||||
int _callTimeout = 0;
|
||||
object_ptr<Ui::SentCodeField> _code = { nullptr };
|
||||
object_ptr<Ui::FadeWrap<Ui::FlatLabel>> _error = { nullptr };
|
||||
object_ptr<Ui::FlatLabel> _callLabel = { nullptr };
|
||||
object_ptr<Ui::RoundButton> _fragment = { nullptr };
|
||||
mtpRequestId _requestId = 0;
|
||||
Ui::SentCodeCall _call;
|
||||
|
||||
@@ -174,11 +183,9 @@ void ChangePhone::EnterPhone::prepare() {
|
||||
this,
|
||||
tr::lng_change_phone_new_description(tr::now),
|
||||
st::changePhoneLabel);
|
||||
const auto errorSkip = st::boxLittleSkip
|
||||
+ st::changePhoneError.style.font->height;
|
||||
description->moveToLeft(
|
||||
st::boxPadding.left(),
|
||||
_phone->y() + _phone->height() + errorSkip + st::boxLittleSkip);
|
||||
_phone->y() + _phone->height() + ErrorSkip() + st::boxLittleSkip);
|
||||
|
||||
setDimensions(
|
||||
st::boxWidth,
|
||||
@@ -221,6 +228,7 @@ void ChangePhone::EnterPhone::sendPhoneDone(
|
||||
return false;
|
||||
};
|
||||
auto codeLength = 0;
|
||||
auto codeByFragmentUrl = QString();
|
||||
const auto hasLength = data.vtype().match([&](
|
||||
const MTPDauth_sentCodeTypeApp &typeData) {
|
||||
LOG(("Error: should not be in-app code!"));
|
||||
@@ -231,6 +239,7 @@ void ChangePhone::EnterPhone::sendPhoneDone(
|
||||
return true;
|
||||
}, [&](const MTPDauth_sentCodeTypeFragmentSms &typeData) {
|
||||
codeLength = typeData.vlength().v;
|
||||
codeByFragmentUrl = qs(typeData.vurl());
|
||||
return true;
|
||||
}, [&](const MTPDauth_sentCodeTypeCall &typeData) {
|
||||
codeLength = typeData.vlength().v;
|
||||
@@ -263,6 +272,7 @@ void ChangePhone::EnterPhone::sendPhoneDone(
|
||||
_controller,
|
||||
phoneNumber,
|
||||
phoneCodeHash,
|
||||
codeByFragmentUrl,
|
||||
codeLength,
|
||||
callTimeout),
|
||||
Ui::LayerOption::KeepOther);
|
||||
@@ -307,18 +317,21 @@ ChangePhone::EnterCode::EnterCode(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const QString &phone,
|
||||
const QString &hash,
|
||||
const QString &openUrl,
|
||||
int codeLength,
|
||||
int callTimeout)
|
||||
: _controller(controller)
|
||||
, _api(&controller->session().mtp())
|
||||
, _phone(phone)
|
||||
, _hash(hash)
|
||||
, _openUrl(openUrl)
|
||||
, _codeLength(codeLength)
|
||||
, _callTimeout(callTimeout)
|
||||
, _call([this] { sendCall(); }, [this] { updateCall(); }) {
|
||||
}
|
||||
|
||||
void ChangePhone::EnterCode::prepare() {
|
||||
const auto width = st::boxWidth;
|
||||
setTitle(tr::lng_change_phone_title());
|
||||
|
||||
const auto descriptionText = tr::lng_change_phone_code_description(
|
||||
@@ -332,44 +345,69 @@ void ChangePhone::EnterCode::prepare() {
|
||||
st::changePhoneLabel);
|
||||
description->moveToLeft(st::boxPadding.left(), 0);
|
||||
|
||||
const auto submitInput = [=] { submit(_code->getDigitsOnly()); };
|
||||
|
||||
const auto phoneValue = QString();
|
||||
_code.create(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
tr::lng_change_phone_code_title(),
|
||||
phoneValue);
|
||||
_code->setAutoSubmit(_codeLength, [=] { submit(); });
|
||||
_code->setAutoSubmit(_codeLength, submitInput);
|
||||
_code->setChangedCallback([=] { hideError(); });
|
||||
|
||||
_code->resize(st::boxWidth - 2 * st::boxPadding.left(), _code->height());
|
||||
_code->resize(width - 2 * st::boxPadding.left(), _code->height());
|
||||
_code->moveToLeft(st::boxPadding.left(), description->bottomNoMargins());
|
||||
connect(_code, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_code, &Ui::InputField::submitted, submitInput);
|
||||
|
||||
setDimensions(st::boxWidth, countHeight());
|
||||
if (!_openUrl.isEmpty()) {
|
||||
_fragment.create(
|
||||
this,
|
||||
tr::lng_intro_fragment_button(),
|
||||
st::fragmentBoxButton);
|
||||
_fragment->setClickedCallback([=] { File::OpenUrl(_openUrl); });
|
||||
_fragment->setTextTransform(
|
||||
Ui::RoundButton::TextTransform::NoTransform);
|
||||
const auto codeBottom = _code->y() + _code->height();
|
||||
_fragment->setFullWidth(_code->width());
|
||||
_fragment->moveToLeft(
|
||||
(width - _fragment->width()) / 2,
|
||||
codeBottom + ErrorSkip() + st::boxLittleSkip);
|
||||
}
|
||||
|
||||
_controller->session().account().setHandleLoginCode([=](QString code) {
|
||||
submit(code);
|
||||
});
|
||||
boxClosing(
|
||||
) | rpl::start_with_next([controller = _controller] {
|
||||
controller->session().account().setHandleLoginCode(nullptr);
|
||||
}, lifetime());
|
||||
|
||||
setDimensions(width, countHeight());
|
||||
|
||||
if (_callTimeout > 0) {
|
||||
_call.setStatus({ Ui::SentCodeCall::State::Waiting, _callTimeout });
|
||||
updateCall();
|
||||
}
|
||||
|
||||
addButton(tr::lng_change_phone_new_submit(), [=] { submit(); });
|
||||
addButton(tr::lng_change_phone_new_submit(), submitInput);
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
}
|
||||
|
||||
int ChangePhone::EnterCode::countHeight() {
|
||||
const auto errorSkip = st::boxLittleSkip
|
||||
+ st::changePhoneError.style.font->height;
|
||||
return _code->bottomNoMargins() + errorSkip + 3 * st::boxLittleSkip;
|
||||
int ChangePhone::EnterCode::countHeight() const {
|
||||
return _code->bottomNoMargins()
|
||||
+ ErrorSkip()
|
||||
+ 3 * st::boxLittleSkip
|
||||
+ (_fragment ? _fragment->height() : 0);
|
||||
}
|
||||
|
||||
void ChangePhone::EnterCode::submit() {
|
||||
void ChangePhone::EnterCode::submit(const QString &code) {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
hideError();
|
||||
|
||||
const auto session = &_controller->session();
|
||||
const auto code = _code->getDigitsOnly();
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
_requestId = session->api().request(MTPaccount_ChangePhone(
|
||||
MTP_string(_phone),
|
||||
|
||||
@@ -25,7 +25,14 @@ DownloadPathBox::DownloadPathBox(
|
||||
, _path(Core::App().settings().downloadPath())
|
||||
, _pathBookmark(Core::App().settings().downloadPathBookmark())
|
||||
, _group(std::make_shared<Ui::RadioenumGroup<Directory>>(typeFromPath(_path)))
|
||||
, _default(this, _group, Directory::Downloads, tr::lng_download_path_default_radio(tr::now), st::defaultBoxCheckbox)
|
||||
, _default(Core::App().canReadDefaultDownloadPath(true)
|
||||
? object_ptr<Ui::Radioenum<Directory>>(
|
||||
this,
|
||||
_group,
|
||||
Directory::Downloads,
|
||||
tr::lng_download_path_default_radio(tr::now),
|
||||
st::defaultBoxCheckbox)
|
||||
: nullptr)
|
||||
, _temp(this, _group, Directory::Temp, tr::lng_download_path_temp_radio(tr::now), st::defaultBoxCheckbox)
|
||||
, _dir(this, _group, Directory::Custom, tr::lng_download_path_dir_radio(tr::now), st::defaultBoxCheckbox)
|
||||
, _pathLink(this, QString(), st::boxLinkButton) {
|
||||
@@ -50,7 +57,7 @@ void DownloadPathBox::updateControlsVisibility() {
|
||||
auto custom = (_group->value() == Directory::Custom);
|
||||
_pathLink->setVisible(custom);
|
||||
|
||||
auto newHeight = st::boxOptionListPadding.top() + _default->getMargins().top() + _default->heightNoMargins() + st::boxOptionListSkip + _temp->heightNoMargins() + st::boxOptionListSkip + _dir->heightNoMargins();
|
||||
auto newHeight = st::boxOptionListPadding.top() + (_default ? _default->getMargins().top() + _default->heightNoMargins() : 0) + st::boxOptionListSkip + _temp->heightNoMargins() + st::boxOptionListSkip + _dir->heightNoMargins();
|
||||
if (custom) {
|
||||
newHeight += st::downloadPathSkip + _pathLink->height();
|
||||
}
|
||||
@@ -62,8 +69,10 @@ void DownloadPathBox::updateControlsVisibility() {
|
||||
void DownloadPathBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_default->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), st::boxOptionListPadding.top() + _default->getMargins().top());
|
||||
_temp->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _default->bottomNoMargins() + st::boxOptionListSkip);
|
||||
if (_default) {
|
||||
_default->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), st::boxOptionListPadding.top() + _default->getMargins().top());
|
||||
}
|
||||
_temp->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), (_default ? _default->bottomNoMargins() : 0) + st::boxOptionListSkip);
|
||||
_dir->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _temp->bottomNoMargins() + st::boxOptionListSkip);
|
||||
auto inputx = st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultCheck.diameter + st::defaultBoxCheckbox.textPosition.x();
|
||||
auto inputy = _dir->bottomNoMargins() + st::downloadPathSkip;
|
||||
|
||||
@@ -477,6 +477,7 @@ object_ptr<Ui::RpWidget> Controller::createPhotoEdit() {
|
||||
st::defaultUserpicButton),
|
||||
st::editPeerPhotoMargins);
|
||||
_controls.photo = photoWrap->entity();
|
||||
_controls.photo->showCustomOnChosen();
|
||||
|
||||
return photoWrap;
|
||||
}
|
||||
|
||||
@@ -595,11 +595,9 @@ void Application::saveSettings() {
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
bool Application::canSaveFileWithoutAskingForPath() const {
|
||||
if (Core::App().settings().askDownloadPath()) {
|
||||
return false;
|
||||
} else if (KSandbox::isInside()
|
||||
&& Core::App().settings().downloadPath().isEmpty()) {
|
||||
bool Application::canReadDefaultDownloadPath(bool always) const {
|
||||
if (KSandbox::isInside()
|
||||
&& (always || Core::App().settings().downloadPath().isEmpty())) {
|
||||
const auto path = QStandardPaths::writableLocation(
|
||||
QStandardPaths::DownloadLocation);
|
||||
return base::CanReadDirectory(path);
|
||||
@@ -607,6 +605,11 @@ bool Application::canSaveFileWithoutAskingForPath() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::canSaveFileWithoutAskingForPath() const {
|
||||
return !Core::App().settings().askDownloadPath()
|
||||
&& canReadDefaultDownloadPath();
|
||||
}
|
||||
|
||||
MTP::Config &Application::fallbackProductionConfig() const {
|
||||
if (!_fallbackProductionConfig) {
|
||||
_fallbackProductionConfig = std::make_unique<MTP::Config>(
|
||||
|
||||
@@ -178,6 +178,8 @@ public:
|
||||
[[nodiscard]] Settings &settings();
|
||||
void saveSettingsDelayed(crl::time delay = kDefaultSaveDelay);
|
||||
void saveSettings();
|
||||
|
||||
[[nodiscard]] bool canReadDefaultDownloadPath(bool always = false) const;
|
||||
[[nodiscard]] bool canSaveFileWithoutAskingForPath() const;
|
||||
|
||||
// Fallback config and proxy.
|
||||
|
||||
@@ -84,6 +84,14 @@ std::map<int, const char*> BetaLogs() {
|
||||
"- Set a public photo for those who are restricted to see "
|
||||
"your profile photo in the Privacy Settings.\n"
|
||||
|
||||
"- Bug fixes and other minor improvements.\n"
|
||||
},
|
||||
{
|
||||
4004003,
|
||||
"- Support for anonymous numbers from the Fragment.com platform.\n"
|
||||
|
||||
"- Fix a crash in own profile photo updating.\n"
|
||||
|
||||
"- Bug fixes and other minor improvements.\n"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,8 +24,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtGui/QDesktopServices>
|
||||
|
||||
#include <ksandbox.h>
|
||||
|
||||
bool filedialogGetSaveFile(
|
||||
QPointer<QWidget> parent,
|
||||
QString &file,
|
||||
@@ -173,15 +171,12 @@ QString DefaultDownloadPathFolder(not_null<Main::Session*> session) {
|
||||
}
|
||||
|
||||
QString DefaultDownloadPath(not_null<Main::Session*> session) {
|
||||
const auto standardLocation = QStandardPaths::writableLocation(
|
||||
QStandardPaths::DownloadLocation);
|
||||
const auto realDefaultPath = standardLocation
|
||||
const auto realDefaultPath = QStandardPaths::writableLocation(
|
||||
QStandardPaths::DownloadLocation)
|
||||
+ '/'
|
||||
+ DefaultDownloadPathFolder(session)
|
||||
+ '/';
|
||||
if (KSandbox::isInside()
|
||||
&& Core::App().settings().downloadPath().isEmpty()
|
||||
&& !base::CanReadDirectory(standardLocation)) {
|
||||
if (!Core::App().canReadDefaultDownloadPath()) {
|
||||
QStringList files;
|
||||
QByteArray remoteContent;
|
||||
const auto success = Platform::FileDialog::Get(
|
||||
|
||||
@@ -49,6 +49,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "settings/settings_chat.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "mainwidget.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "inline_bots/bot_attach_web_view.h"
|
||||
@@ -792,6 +793,25 @@ bool ResolvePremiumOffer(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResolveLoginCode(
|
||||
Window::SessionController *controller,
|
||||
const Match &match,
|
||||
const QVariant &context) {
|
||||
const auto loginCode = match->captured(2);
|
||||
if (loginCode.isEmpty()) {
|
||||
return false;
|
||||
};
|
||||
(controller
|
||||
? controller->session().account()
|
||||
: Core::App().activeAccount()).handleLoginCode(loginCode);
|
||||
if (controller) {
|
||||
controller->window().activate();
|
||||
} else if (const auto window = Core::App().activeWindow()) {
|
||||
window->activate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
|
||||
@@ -864,6 +884,10 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
|
||||
u"premium_offer/?(\\?.+)?(#|$)"_q,
|
||||
ResolvePremiumOffer,
|
||||
},
|
||||
{
|
||||
u"^login/?(\\?code=([0-9]+))(&|$)"_q,
|
||||
ResolveLoginCode
|
||||
},
|
||||
{
|
||||
u"^([^\\?]+)(\\?|#|$)"_q,
|
||||
HandleUnknown
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 4004002;
|
||||
constexpr auto AppVersionStr = "4.4.2";
|
||||
constexpr auto AppVersion = 4004003;
|
||||
constexpr auto AppVersionStr = "4.4.3";
|
||||
constexpr auto AppBetaVersion = true;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -356,24 +356,55 @@ FormatResult CountriesInstance::format(FormatArgs args) {
|
||||
const auto codeSize = int(bestCallingCodePtr->callingCode.size());
|
||||
|
||||
if (args.onlyGroups && args.incomplete) {
|
||||
auto groups = args.skipCode
|
||||
auto initialGroups = args.skipCode
|
||||
? QVector<int>()
|
||||
: QVector<int>{ codeSize };
|
||||
auto groupSize = 0;
|
||||
auto initialGroupsSize = 0;
|
||||
if (bestCallingCodePtr->patterns.empty()) {
|
||||
return FormatResult{ .groups = std::move(groups) };
|
||||
return FormatResult{ .groups = std::move(initialGroups) };
|
||||
}
|
||||
for (const auto &c : bestCallingCodePtr->patterns.front()) {
|
||||
if (c == ' ') {
|
||||
groups.push_back(base::take(groupSize));
|
||||
} else {
|
||||
groupSize++;
|
||||
auto bestGroups = initialGroups;
|
||||
auto bestGroupsSize = initialGroupsSize;
|
||||
auto bestPatternMaxMatches = -1;
|
||||
for (const auto &pattern : bestCallingCodePtr->patterns) {
|
||||
auto groups = initialGroups;
|
||||
auto groupSize = initialGroupsSize;
|
||||
auto lastSpacesCount = 0;
|
||||
auto maxMatchedDigits = 0;
|
||||
auto isNotBestPattern = false;
|
||||
for (auto i = 0; i < pattern.size(); i++) {
|
||||
const auto c = pattern.at(i);
|
||||
if (c.isDigit()) {
|
||||
const auto n = (i - lastSpacesCount) + codeSize;
|
||||
if (n < phoneNumber.size()) {
|
||||
if (phoneNumber.at(n) == c) {
|
||||
maxMatchedDigits++;
|
||||
} else {
|
||||
isNotBestPattern = true;
|
||||
}
|
||||
} else {
|
||||
isNotBestPattern = true;
|
||||
}
|
||||
}
|
||||
if (c.isSpace()) {
|
||||
groups.push_back(base::take(groupSize));
|
||||
lastSpacesCount++;
|
||||
} else {
|
||||
groupSize++;
|
||||
}
|
||||
}
|
||||
if (maxMatchedDigits > bestPatternMaxMatches) {
|
||||
bestPatternMaxMatches = isNotBestPattern
|
||||
? -1
|
||||
: maxMatchedDigits;
|
||||
bestGroups = std::move(groups);
|
||||
bestGroupsSize = groupSize;
|
||||
}
|
||||
}
|
||||
if (groupSize) {
|
||||
groups.push_back(base::take(groupSize));
|
||||
if (bestGroupsSize) {
|
||||
bestGroups.push_back(base::take(bestGroupsSize));
|
||||
}
|
||||
return FormatResult{ .groups = std::move(groups) };
|
||||
return FormatResult{ .groups = std::move(bestGroups) };
|
||||
}
|
||||
|
||||
const auto formattedPart = phoneNumber.mid(codeSize);
|
||||
|
||||
@@ -89,12 +89,10 @@ void PaintRowDate(
|
||||
const auto lastDate = lastTime.date();
|
||||
|
||||
const auto dt = [&] {
|
||||
const auto wasSameDay = (lastDate == nowDate);
|
||||
const auto wasRecently = qAbs(lastTime.secsTo(now)) < kRecentlyInSeconds;
|
||||
if (wasSameDay || wasRecently) {
|
||||
if ((lastDate == nowDate)
|
||||
|| (qAbs(lastTime.secsTo(now)) < kRecentlyInSeconds)) {
|
||||
return QLocale().toString(lastTime.time(), QLocale::ShortFormat);
|
||||
} else if (lastDate.year() == nowDate.year()
|
||||
&& lastDate.weekNumber() == nowDate.weekNumber()) {
|
||||
} else if (qAbs(lastDate.daysTo(nowDate)) < 7) {
|
||||
return langDayOfWeek(lastDate);
|
||||
} else {
|
||||
return QLocale().toString(lastDate, QLocale::ShortFormat);
|
||||
|
||||
@@ -1431,12 +1431,18 @@ void HistoryItem::applyEdition(const MTPDmessageService &message) {
|
||||
if (wasGrouped) {
|
||||
history()->owner().groups().unregisterMessage(this);
|
||||
}
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
reply->clearData(this);
|
||||
}
|
||||
clearDependencyMessage();
|
||||
UpdateComponents(0);
|
||||
createServiceFromMtp(message);
|
||||
applyServiceDateEdition(message);
|
||||
finishEditionToEmpty();
|
||||
} else if (isService()) {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
reply->clearData(this);
|
||||
}
|
||||
clearDependencyMessage();
|
||||
UpdateComponents(0);
|
||||
createServiceFromMtp(message);
|
||||
|
||||
@@ -141,7 +141,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallBarContentByCall(
|
||||
userpic.peer->loadUserpic();
|
||||
auto image = userpic.peer->generateUserpicImage(
|
||||
userpic.view,
|
||||
userpicSize);
|
||||
userpicSize * style::DevicePixelRatio());
|
||||
userpic.uniqueKey = userpic.peer->userpicUniqueKey(userpic.view);
|
||||
state->current.users.push_back({
|
||||
.userpic = std::move(image),
|
||||
|
||||
@@ -88,7 +88,7 @@ rpl::producer<Ui::RequestsBarContent> RequestsBarContentByPeer(
|
||||
userpic.peer->loadUserpic();
|
||||
auto image = userpic.peer->generateUserpicImage(
|
||||
userpic.view,
|
||||
userpicSize);
|
||||
userpicSize * style::DevicePixelRatio());
|
||||
userpic.uniqueKey = userpic.peer->userpicUniqueKey(userpic.view);
|
||||
state->current.users.push_back({
|
||||
.userpic = std::move(image),
|
||||
|
||||
@@ -45,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "info/info_controller.h"
|
||||
#include "info/info_memento.h"
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
#include "info/profile/info_profile_phone_menu.h"
|
||||
#include "info/profile/info_profile_values.h"
|
||||
#include "info/profile/info_profile_text.h"
|
||||
#include "support/support_helper.h"
|
||||
@@ -391,10 +392,17 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
|
||||
user->session().supportHelper().infoTextValue(user));
|
||||
}
|
||||
|
||||
addInfoOneLine(
|
||||
tr::lng_info_mobile_label(),
|
||||
PhoneOrHiddenValue(user),
|
||||
tr::lng_profile_copy_phone(tr::now));
|
||||
{
|
||||
const auto phoneLabel = addInfoOneLine(
|
||||
tr::lng_info_mobile_label(),
|
||||
PhoneOrHiddenValue(user),
|
||||
tr::lng_profile_copy_phone(tr::now)).text;
|
||||
const auto hook = [=](Ui::FlatLabel::ContextMenuRequest request) {
|
||||
phoneLabel->fillContextMenu(request);
|
||||
AddPhoneMenu(request.menu, user);
|
||||
};
|
||||
phoneLabel->setContextMenuHook(hook);
|
||||
}
|
||||
auto label = user->isBot()
|
||||
? tr::lng_info_about_label()
|
||||
: tr::lng_info_bio_label();
|
||||
|
||||
155
Telegram/SourceFiles/info/profile/info_profile_phone_menu.cpp
Normal file
155
Telegram/SourceFiles/info/profile/info_profile_phone_menu.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
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 "info/profile/info_profile_phone_menu.h"
|
||||
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/menu/menu_action.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "styles/style_chat.h" // expandedMenuSeparator.
|
||||
|
||||
namespace Info {
|
||||
namespace Profile {
|
||||
namespace {
|
||||
|
||||
class TextItem final : public Ui::Menu::ItemBase {
|
||||
public:
|
||||
TextItem(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
const style::Menu &st,
|
||||
rpl::producer<TextWithEntities> &&text);
|
||||
|
||||
not_null<QAction*> action() const override;
|
||||
bool isEnabled() const override;
|
||||
|
||||
protected:
|
||||
int contentHeight() const override;
|
||||
|
||||
private:
|
||||
const base::unique_qptr<Ui::FlatLabel> _label;
|
||||
const not_null<QAction*> _dummyAction;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] int CountMinWidthForHeight(
|
||||
not_null<Ui::FlatLabel*> label,
|
||||
int basicWidth,
|
||||
int heightLimit) {
|
||||
const auto height = [&](int width) {
|
||||
label->resizeToWidth(width);
|
||||
return label->height();
|
||||
};
|
||||
auto widthMin = basicWidth;
|
||||
auto widthMax = label->naturalWidth();
|
||||
if (height(widthMin) <= heightLimit || height(widthMax) > heightLimit) {
|
||||
return basicWidth;
|
||||
}
|
||||
while (widthMin + 1 < widthMax) {
|
||||
const auto middle = (widthMin + widthMax) / 2;
|
||||
if (height(middle) > heightLimit) {
|
||||
widthMin = middle;
|
||||
} else {
|
||||
widthMax = middle;
|
||||
}
|
||||
}
|
||||
return widthMax;
|
||||
}
|
||||
|
||||
TextItem::TextItem(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
const style::Menu &st,
|
||||
rpl::producer<TextWithEntities> &&text)
|
||||
: ItemBase(parent, st)
|
||||
, _label(base::make_unique_q<Ui::FlatLabel>(
|
||||
this,
|
||||
std::move(text),
|
||||
st::historyMessagesTTLLabel))
|
||||
, _dummyAction(Ui::CreateChild<QAction>(parent.get())) {
|
||||
// Try to fit the phrase in two lines.
|
||||
const auto limit = st::historyMessagesTTLLabel.style.font->height * 2;
|
||||
const auto min1 = st::historyMessagesTTLLabel.minWidth;
|
||||
const auto min2 = CountMinWidthForHeight(_label.get(), min1, limit);
|
||||
const auto added = st.itemPadding.left() + st.itemPadding.right();
|
||||
setMinWidth(std::max(min1, min2) + added);
|
||||
|
||||
sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &s) {
|
||||
if (s.width() <= added) {
|
||||
return;
|
||||
}
|
||||
_label->resizeToWidth(s.width() - added);
|
||||
_label->moveToLeft(
|
||||
st.itemPadding.left(),
|
||||
(s.height() - _label->height()) / 2);
|
||||
}, lifetime());
|
||||
|
||||
_label->resizeToWidth(parent->width() - added);
|
||||
initResizeHook(parent->sizeValue());
|
||||
}
|
||||
|
||||
not_null<QAction*> TextItem::action() const {
|
||||
return _dummyAction;
|
||||
}
|
||||
|
||||
bool TextItem::isEnabled() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
int TextItem::contentHeight() const {
|
||||
return _label->height();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AddPhoneMenu(not_null<Ui::PopupMenu*> menu, not_null<UserData*> user) {
|
||||
if (user->isSelf()) {
|
||||
return;
|
||||
}
|
||||
using Strings = std::vector<QString>;
|
||||
const auto prefixes = user->session().account().appConfig().get<Strings>(
|
||||
u"fragment_prefixes"_q,
|
||||
std::vector<QString>());
|
||||
{
|
||||
const auto proj = [&phone = user->phone()](const QString &p) {
|
||||
return phone.startsWith(p);
|
||||
};
|
||||
if (ranges::none_of(prefixes, proj)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const auto domains = user->session().account().appConfig().get<Strings>(
|
||||
u"whitelisted_domains"_q,
|
||||
std::vector<QString>());
|
||||
const auto proj = [&, domain = u"fragment"_q](const QString &p) {
|
||||
return p.contains(domain);
|
||||
};
|
||||
const auto it = ranges::find_if(domains, proj);
|
||||
if (it == end(domains)) {
|
||||
return;
|
||||
}
|
||||
|
||||
menu->addSeparator(&st::expandedMenuSeparator);
|
||||
const auto link = Ui::Text::Link(
|
||||
tr::lng_info_mobile_context_menu_fragment_about_link(tr::now),
|
||||
*it);
|
||||
menu->addAction(base::make_unique_q<TextItem>(
|
||||
menu->menu(),
|
||||
st::reactionMenu.menu,
|
||||
tr::lng_info_mobile_context_menu_fragment_about(
|
||||
lt_link,
|
||||
rpl::single(link),
|
||||
Ui::Text::RichLangValue)));
|
||||
}
|
||||
|
||||
} // namespace Profile
|
||||
} // namespace Info
|
||||
22
Telegram/SourceFiles/info/profile/info_profile_phone_menu.h
Normal file
22
Telegram/SourceFiles/info/profile/info_profile_phone_menu.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
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
|
||||
|
||||
class UserData;
|
||||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Info {
|
||||
namespace Profile {
|
||||
|
||||
void AddPhoneMenu(not_null<Ui::PopupMenu*> menu, not_null<UserData*> user);
|
||||
|
||||
} // namespace Profile
|
||||
} // namespace Info
|
||||
@@ -85,9 +85,17 @@ introCoverDuration: 200;
|
||||
introNextButton: RoundButton(defaultActiveButton) {
|
||||
width: 300px;
|
||||
height: 42px;
|
||||
radius: 6px;
|
||||
textTop: 11px;
|
||||
font: font(boxFontSize semibold);
|
||||
}
|
||||
introFragmentIcon: icon{{ "fragment", activeButtonFg }};
|
||||
introFragmentIconOver: icon{{ "fragment", activeButtonFgOver }};
|
||||
introFragmentButton: RoundButton(introNextButton) {
|
||||
icon: introFragmentIcon;
|
||||
iconOver: introFragmentIconOver;
|
||||
iconPosition: point(-10px, 9px);
|
||||
}
|
||||
|
||||
introStepFieldTop: 96px;
|
||||
introPhoneTop: 6px;
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "intro/intro_signup.h"
|
||||
#include "intro/intro_password_check.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
@@ -99,8 +100,15 @@ CodeWidget::CodeWidget(
|
||||
|
||||
_code->setDigitsCountMax(getData()->codeLength);
|
||||
|
||||
setTitleText(rpl::single(Ui::FormatPhone(getData()->phone)));
|
||||
setTitleText(getData()->codeByFragmentUrl.isEmpty()
|
||||
? rpl::single(Ui::FormatPhone(getData()->phone))
|
||||
: tr::lng_intro_fragment_title());
|
||||
updateDescText();
|
||||
|
||||
account->setHandleLoginCode([=](const QString &code) {
|
||||
_code->setText(code);
|
||||
submitCode();
|
||||
});
|
||||
}
|
||||
|
||||
void CodeWidget::refreshLang() {
|
||||
@@ -117,10 +125,19 @@ int CodeWidget::errorTop() const {
|
||||
|
||||
void CodeWidget::updateDescText() {
|
||||
const auto byTelegram = getData()->codeByTelegram;
|
||||
const auto isFragment = !getData()->codeByFragmentUrl.isEmpty();
|
||||
setDescriptionText(
|
||||
(byTelegram ? tr::lng_code_from_telegram : tr::lng_code_desc)(
|
||||
Ui::Text::RichLangValue));
|
||||
if (getData()->codeByTelegram) {
|
||||
isFragment
|
||||
? tr::lng_intro_fragment_about(
|
||||
lt_phone_number,
|
||||
rpl::single(TextWithEntities{
|
||||
.text = Ui::FormatPhone(getData()->phone)
|
||||
}),
|
||||
Ui::Text::RichLangValue)
|
||||
: (byTelegram ? tr::lng_code_from_telegram : tr::lng_code_desc)(
|
||||
Ui::Text::RichLangValue));
|
||||
if (isFragment) {
|
||||
} else if (getData()->codeByTelegram) {
|
||||
_noTelegramCode->show();
|
||||
_callTimer.cancel();
|
||||
} else {
|
||||
@@ -204,6 +221,7 @@ void CodeWidget::activate() {
|
||||
|
||||
void CodeWidget::finished() {
|
||||
Step::finished();
|
||||
account().setHandleLoginCode(nullptr);
|
||||
_checkRequestTimer.cancel();
|
||||
_callTimer.cancel();
|
||||
apiClear();
|
||||
@@ -300,7 +318,7 @@ void CodeWidget::codeSubmitFail(const MTP::Error &error) {
|
||||
|
||||
void CodeWidget::codeChanged() {
|
||||
hideError();
|
||||
submit();
|
||||
submitCode();
|
||||
}
|
||||
|
||||
void CodeWidget::sendCall() {
|
||||
@@ -362,10 +380,18 @@ void CodeWidget::gotPassword(const MTPaccount_Password &result) {
|
||||
}
|
||||
|
||||
void CodeWidget::submit() {
|
||||
if (getData()->codeByFragmentUrl.isEmpty()) {
|
||||
submitCode();
|
||||
} else {
|
||||
File::OpenUrl(getData()->codeByFragmentUrl);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeWidget::submitCode() {
|
||||
const auto text = QString(
|
||||
_code->getLastText()
|
||||
).remove(
|
||||
QRegularExpression("[^\\d]")
|
||||
TextUtilities::RegExpDigitsExclude()
|
||||
).mid(0, getData()->codeLength);
|
||||
|
||||
if (_sentRequest
|
||||
@@ -393,6 +419,18 @@ void CodeWidget::submit() {
|
||||
}).handleFloodErrors().send();
|
||||
}
|
||||
|
||||
rpl::producer<QString> CodeWidget::nextButtonText() const {
|
||||
return getData()->codeByFragmentUrl.isEmpty()
|
||||
? Step::nextButtonText()
|
||||
: tr::lng_intro_fragment_button();
|
||||
}
|
||||
|
||||
const style::RoundButton *CodeWidget::nextButtonStyle() const {
|
||||
return !getData()->codeByFragmentUrl.isEmpty()
|
||||
? &st::introFragmentButton
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void CodeWidget::noTelegramCode() {
|
||||
if (_noTelegramCodeRequestId) {
|
||||
return;
|
||||
|
||||
@@ -55,6 +55,8 @@ public:
|
||||
void finished() override;
|
||||
void cancelled() override;
|
||||
void submit() override;
|
||||
rpl::producer<QString> nextButtonText() const override;
|
||||
const style::RoundButton *nextButtonStyle() const override;
|
||||
|
||||
void updateDescText();
|
||||
|
||||
@@ -83,6 +85,8 @@ private:
|
||||
void noTelegramCodeDone(const MTPauth_SentCode &result);
|
||||
void noTelegramCodeFail(const MTP::Error &result);
|
||||
|
||||
void submitCode();
|
||||
|
||||
void stopCheck();
|
||||
|
||||
object_ptr<Ui::LinkButton> _noTelegramCode;
|
||||
|
||||
@@ -34,6 +34,8 @@ SignupWidget::SignupWidget(
|
||||
, _first(this, st::introName, tr::lng_signup_firstname())
|
||||
, _last(this, st::introName, tr::lng_signup_lastname())
|
||||
, _invertOrder(langFirstNameGoesSecond()) {
|
||||
_photo->showCustomOnChosen();
|
||||
|
||||
Lang::Updated(
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshLang();
|
||||
|
||||
@@ -119,6 +119,10 @@ rpl::producer<QString> Step::nextButtonText() const {
|
||||
return tr::lng_intro_next();
|
||||
}
|
||||
|
||||
const style::RoundButton *Step::nextButtonStyle() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Step::goBack() {
|
||||
if (_goCallback) {
|
||||
_goCallback(nullptr, StackAction::Back, Animate::Back);
|
||||
|
||||
@@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/effects/animations.h"
|
||||
|
||||
namespace style {
|
||||
struct RoundButton;
|
||||
} // namespace style;
|
||||
|
||||
namespace Main {
|
||||
class Account;
|
||||
} // namespace Main;
|
||||
@@ -77,6 +81,7 @@ public:
|
||||
|
||||
virtual void submit() = 0;
|
||||
[[nodiscard]] virtual rpl::producer<QString> nextButtonText() const;
|
||||
[[nodiscard]] virtual const style::RoundButton *nextButtonStyle() const;
|
||||
|
||||
[[nodiscard]] int contentLeft() const;
|
||||
[[nodiscard]] int contentTop() const;
|
||||
|
||||
@@ -74,6 +74,7 @@ Widget::Widget(
|
||||
: RpWidget(parent)
|
||||
, _account(account)
|
||||
, _data(details::Data{ .controller = controller })
|
||||
, _nextStyle(&st::introNextButton)
|
||||
, _back(this, object_ptr<Ui::IconButton>(this, st::introBackButton))
|
||||
, _settings(
|
||||
this,
|
||||
@@ -83,7 +84,7 @@ Widget::Widget(
|
||||
st::defaultBoxButton))
|
||||
, _next(
|
||||
this,
|
||||
object_ptr<Ui::RoundButton>(this, nullptr, st::introNextButton))
|
||||
object_ptr<Ui::RoundButton>(this, nullptr, *_nextStyle))
|
||||
, _connecting(std::make_unique<Window::ConnectionState>(
|
||||
this,
|
||||
account,
|
||||
@@ -127,10 +128,6 @@ Widget::Widget(
|
||||
_back->entity()->setClickedCallback([=] { backRequested(); });
|
||||
_back->hide(anim::type::instant);
|
||||
|
||||
_next->entity()->setClickedCallback([=] { getStep()->submit(); });
|
||||
_next->entity()->setTextTransform(
|
||||
Ui::RoundButton::TextTransform::NoTransform);
|
||||
|
||||
if (_changeLanguage) {
|
||||
_changeLanguage->finishAnimating();
|
||||
}
|
||||
@@ -344,13 +341,31 @@ void Widget::historyMove(StackAction action, Animate animate) {
|
||||
if (_terms) {
|
||||
hideAndDestroy(std::exchange(_terms, { nullptr }));
|
||||
}
|
||||
{
|
||||
const auto st = getStep()->nextButtonStyle();
|
||||
const auto nextStyle = st ? st : &st::introNextButton;
|
||||
if (_nextStyle != nextStyle) {
|
||||
_nextStyle = nextStyle;
|
||||
_next = nullptr;
|
||||
_next.create(
|
||||
this,
|
||||
object_ptr<Ui::RoundButton>(this, nullptr, *nextStyle));
|
||||
showControls();
|
||||
updateControlsGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
getStep()->finishInit();
|
||||
getStep()->prepareShowAnimated(wasStep);
|
||||
if (wasStep->hasCover() != getStep()->hasCover()) {
|
||||
_nextTopFrom = wasStep->contentTop() + st::introNextTop;
|
||||
_controlsTopFrom = wasStep->hasCover() ? st::introCoverHeight : 0;
|
||||
_coverShownAnimation.start([this] { updateControlsGeometry(); }, 0., 1., st::introCoverDuration, wasStep->hasCover() ? anim::linear : anim::easeOutCirc);
|
||||
_coverShownAnimation.start(
|
||||
[this] { updateControlsGeometry(); },
|
||||
0.,
|
||||
1.,
|
||||
st::introCoverDuration,
|
||||
wasStep->hasCover() ? anim::linear : anim::easeOutCirc);
|
||||
}
|
||||
|
||||
_stepLifetime.destroy();
|
||||
@@ -665,6 +680,10 @@ void Widget::showControls() {
|
||||
}
|
||||
|
||||
void Widget::setupNextButton() {
|
||||
_next->entity()->setClickedCallback([=] { getStep()->submit(); });
|
||||
_next->entity()->setTextTransform(
|
||||
Ui::RoundButton::TextTransform::NoTransform);
|
||||
|
||||
_next->entity()->setText(getStep()->nextButtonText(
|
||||
) | rpl::filter([](const QString &text) {
|
||||
return !text.isEmpty();
|
||||
@@ -757,13 +776,18 @@ void Widget::resizeEvent(QResizeEvent *e) {
|
||||
}
|
||||
|
||||
void Widget::updateControlsGeometry() {
|
||||
auto shown = _coverShownAnimation.value(1.);
|
||||
const auto skip = st::introSettingsSkip;
|
||||
const auto shown = _coverShownAnimation.value(1.);
|
||||
|
||||
auto controlsTopTo = getStep()->hasCover() ? st::introCoverHeight : 0;
|
||||
auto controlsTop = anim::interpolate(_controlsTopFrom, controlsTopTo, shown);
|
||||
_settings->moveToRight(st::introSettingsSkip, controlsTop + st::introSettingsSkip);
|
||||
const auto controlsTop = anim::interpolate(
|
||||
_controlsTopFrom,
|
||||
getStep()->hasCover() ? st::introCoverHeight : 0,
|
||||
shown);
|
||||
_settings->moveToRight(skip, controlsTop + skip);
|
||||
if (_update) {
|
||||
_update->moveToRight(st::introSettingsSkip + _settings->width() + st::introSettingsSkip, _settings->y());
|
||||
_update->moveToRight(
|
||||
skip + _settings->width() + skip,
|
||||
_settings->y());
|
||||
}
|
||||
_back->moveToLeft(0, controlsTop);
|
||||
|
||||
@@ -779,13 +803,19 @@ void Widget::updateControlsGeometry() {
|
||||
? QRect(0, 0, width(), realNextTop)
|
||||
: QRect());
|
||||
if (_changeLanguage) {
|
||||
_changeLanguage->moveToLeft((width() - _changeLanguage->width()) / 2, _next->y() + _next->height() + _changeLanguage->height());
|
||||
_changeLanguage->moveToLeft(
|
||||
(width() - _changeLanguage->width()) / 2,
|
||||
_next->y() + _next->height() + _changeLanguage->height());
|
||||
}
|
||||
if (_resetAccount) {
|
||||
_resetAccount->moveToLeft((width() - _resetAccount->width()) / 2, height() - st::introResetBottom - _resetAccount->height());
|
||||
_resetAccount->moveToLeft(
|
||||
(width() - _resetAccount->width()) / 2,
|
||||
height() - st::introResetBottom - _resetAccount->height());
|
||||
}
|
||||
if (_terms) {
|
||||
_terms->moveToLeft((width() - _terms->width()) / 2, height() - st::introTermsBottom - _terms->height());
|
||||
_terms->moveToLeft(
|
||||
(width() - _terms->width()) / 2,
|
||||
height() - st::introTermsBottom - _terms->height());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,6 +186,8 @@ private:
|
||||
int _nextTopFrom = 0;
|
||||
int _controlsTopFrom = 0;
|
||||
|
||||
const style::RoundButton *_nextStyle = nullptr;
|
||||
|
||||
object_ptr<Ui::FadeWrap<Ui::IconButton>> _back;
|
||||
object_ptr<Ui::FadeWrap<Ui::RoundButton>> _update = { nullptr };
|
||||
object_ptr<Ui::FadeWrap<Ui::RoundButton>> _settings;
|
||||
|
||||
@@ -602,6 +602,16 @@ void Account::destroyStaleAuthorizationKeys() {
|
||||
}
|
||||
}
|
||||
|
||||
void Account::setHandleLoginCode(Fn<void(QString)> callback) {
|
||||
_handleLoginCode = std::move(callback);
|
||||
}
|
||||
|
||||
void Account::handleLoginCode(const QString &code) const {
|
||||
if (_handleLoginCode) {
|
||||
_handleLoginCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
void Account::resetAuthorizationKeys() {
|
||||
Expects(_mtp != nullptr);
|
||||
|
||||
|
||||
@@ -110,6 +110,9 @@ public:
|
||||
void suggestMainDcId(MTP::DcId mainDcId);
|
||||
void destroyStaleAuthorizationKeys();
|
||||
|
||||
void setHandleLoginCode(Fn<void(QString)> callback);
|
||||
void handleLoginCode(const QString &code) const;
|
||||
|
||||
[[nodiscard]] rpl::lifetime &lifetime() {
|
||||
return _lifetime;
|
||||
}
|
||||
@@ -152,6 +155,8 @@ private:
|
||||
std::unique_ptr<Session> _session;
|
||||
rpl::variable<Session*> _sessionValue;
|
||||
|
||||
Fn<void(QString)> _handleLoginCode = nullptr;
|
||||
|
||||
UserId _sessionUserId = 0;
|
||||
QByteArray _sessionUserSerialized;
|
||||
int32 _sessionUserStreamVersion = 0;
|
||||
|
||||
@@ -198,7 +198,6 @@ QByteArray Session::validTmpPassword() const {
|
||||
|
||||
// Can be called only right before ~Session.
|
||||
void Session::finishLogout() {
|
||||
updates().updateOnline();
|
||||
unlockTerms();
|
||||
data().clear();
|
||||
data().clearLocalStorage();
|
||||
|
||||
@@ -1537,6 +1537,7 @@ bool Instance::Private::onErrorDefault(
|
||||
|
||||
const auto session = getSession(qAbs(dcWithShift));
|
||||
request->needsLayer = true;
|
||||
session->setConnectionNotInited();
|
||||
session->sendPrepared(request);
|
||||
return true;
|
||||
} else if (type == u"CONNECTION_LANG_CODE_INVALID"_q) {
|
||||
|
||||
@@ -257,10 +257,14 @@ void Session::refreshOptions() {
|
||||
}
|
||||
|
||||
void Session::reInitConnection() {
|
||||
_dc->setConnectionInited(false);
|
||||
setConnectionNotInited();
|
||||
restart();
|
||||
}
|
||||
|
||||
void Session::setConnectionNotInited() {
|
||||
_dc->setConnectionInited(false);
|
||||
}
|
||||
|
||||
void Session::stop() {
|
||||
if (_killed) {
|
||||
DEBUG_LOG(("Session Error: can't stop a killed session"));
|
||||
|
||||
@@ -142,6 +142,7 @@ public:
|
||||
|
||||
void start();
|
||||
void reInitConnection();
|
||||
void setConnectionNotInited();
|
||||
|
||||
void restart();
|
||||
void refreshOptions();
|
||||
|
||||
@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "passport/passport_panel_controller.h"
|
||||
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_session.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "passport/passport_panel_edit_document.h"
|
||||
#include "passport/passport_panel_edit_contact.h"
|
||||
@@ -485,7 +487,9 @@ EditContactScheme GetContactScheme(Scope::Type type) {
|
||||
return Ui::FormatPhone(value);
|
||||
};
|
||||
result.postprocess = [](QString value) {
|
||||
return value.replace(QRegularExpression("[^\\d]"), QString());
|
||||
return value.replace(
|
||||
TextUtilities::RegExpDigitsExclude(),
|
||||
QString());
|
||||
};
|
||||
return result;
|
||||
} break;
|
||||
@@ -1319,11 +1323,16 @@ void PanelController::processVerificationNeeded(
|
||||
});
|
||||
const auto box = [&] {
|
||||
if (type == Value::Type::Phone) {
|
||||
return show(VerifyPhoneBox(
|
||||
const auto submit = [=](const QString &code) {
|
||||
_form->verify(value, code);
|
||||
};
|
||||
const auto account = &_form->window()->session().account();
|
||||
account->setHandleLoginCode(submit);
|
||||
const auto box = show(VerifyPhoneBox(
|
||||
text,
|
||||
value->verification.codeLength,
|
||||
[=](const QString &code) { _form->verify(value, code); },
|
||||
|
||||
value->verification.fragmentUrl,
|
||||
submit,
|
||||
value->verification.call ? rpl::single(
|
||||
value->verification.call->getText()
|
||||
) | rpl::then(rpl::duplicate(
|
||||
@@ -1339,6 +1348,11 @@ void PanelController::processVerificationNeeded(
|
||||
) | rpl::map([=](not_null<const Value*> field) {
|
||||
return field->verification.error;
|
||||
}) | rpl::distinct_until_changed()));
|
||||
box->boxClosing(
|
||||
) | rpl::start_with_next([=] {
|
||||
account->setHandleLoginCode(nullptr);
|
||||
}, box->lifetime());
|
||||
return box;
|
||||
} else if (type == Value::Type::Email) {
|
||||
return show(VerifyEmailBox(
|
||||
text,
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "passport/passport_panel_edit_contact.h"
|
||||
|
||||
#include "core/file_utilities.h"
|
||||
#include "passport/passport_panel_controller.h"
|
||||
#include "passport/ui/passport_details_row.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
@@ -26,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "countries/countries_instance.h" // Countries::ExtractPhoneCode.
|
||||
#include "main/main_session.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_passport.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
@@ -39,6 +41,7 @@ public:
|
||||
rpl::producer<QString> title,
|
||||
const QString &text,
|
||||
int codeLength,
|
||||
const QString &openUrl,
|
||||
Fn<void(QString code)> submit,
|
||||
Fn<void()> resend,
|
||||
rpl::producer<QString> call,
|
||||
@@ -54,6 +57,7 @@ private:
|
||||
void setupControls(
|
||||
const QString &text,
|
||||
int codeLength,
|
||||
const QString &openUrl,
|
||||
Fn<void(QString code)> submit,
|
||||
Fn<void()> resend,
|
||||
rpl::producer<QString> call,
|
||||
@@ -72,6 +76,7 @@ VerifyBox::VerifyBox(
|
||||
rpl::producer<QString> title,
|
||||
const QString &text,
|
||||
int codeLength,
|
||||
const QString &openUrl,
|
||||
Fn<void(QString code)> submit,
|
||||
Fn<void()> resend,
|
||||
rpl::producer<QString> call,
|
||||
@@ -81,6 +86,7 @@ VerifyBox::VerifyBox(
|
||||
setupControls(
|
||||
text,
|
||||
codeLength,
|
||||
openUrl,
|
||||
submit,
|
||||
resend,
|
||||
std::move(call),
|
||||
@@ -91,6 +97,7 @@ VerifyBox::VerifyBox(
|
||||
void VerifyBox::setupControls(
|
||||
const QString &text,
|
||||
int codeLength,
|
||||
const QString &openUrl,
|
||||
Fn<void(QString code)> submit,
|
||||
Fn<void()> resend,
|
||||
rpl::producer<QString> call,
|
||||
@@ -130,6 +137,21 @@ void VerifyBox::setupControls(
|
||||
std::move(call),
|
||||
st::boxDividerLabel),
|
||||
small);
|
||||
if (!openUrl.isEmpty()) {
|
||||
const auto button = _content->add(
|
||||
object_ptr<Ui::RoundButton>(
|
||||
_content,
|
||||
tr::lng_intro_fragment_button(),
|
||||
st::fragmentBoxButton),
|
||||
small);
|
||||
_content->widthValue(
|
||||
) | rpl::start_with_next([=](int w) {
|
||||
button->setFullWidth(w - small.left() - small.right());
|
||||
}, button->lifetime());
|
||||
button->setClickedCallback([=] { ::File::OpenUrl(openUrl); });
|
||||
button->setTextTransform(
|
||||
Ui::RoundButton::TextTransform::NoTransform);
|
||||
}
|
||||
if (resend) {
|
||||
auto link = TextWithEntities{ tr::lng_cloud_password_resend(tr::now) };
|
||||
link.entities.push_back({
|
||||
@@ -144,9 +166,7 @@ void VerifyBox::setupControls(
|
||||
link
|
||||
) | rpl::then(rpl::duplicate(
|
||||
resent
|
||||
) | rpl::map([](const QString &value) {
|
||||
return TextWithEntities{ value };
|
||||
})),
|
||||
) | rpl::map(TextWithEntities::Simple)),
|
||||
st::boxDividerLabel),
|
||||
small);
|
||||
std::move(
|
||||
@@ -392,6 +412,7 @@ void PanelEditContact::save(const QString &value) {
|
||||
object_ptr<Ui::BoxContent> VerifyPhoneBox(
|
||||
const QString &phone,
|
||||
int codeLength,
|
||||
const QString &openUrl,
|
||||
Fn<void(QString code)> submit,
|
||||
rpl::producer<QString> call,
|
||||
rpl::producer<QString> error) {
|
||||
@@ -402,6 +423,7 @@ object_ptr<Ui::BoxContent> VerifyPhoneBox(
|
||||
lt_phone,
|
||||
Ui::FormatPhone(phone)),
|
||||
codeLength,
|
||||
openUrl,
|
||||
submit,
|
||||
nullptr,
|
||||
std::move(call),
|
||||
@@ -420,6 +442,7 @@ object_ptr<Ui::BoxContent> VerifyEmailBox(
|
||||
tr::lng_passport_email_title(),
|
||||
tr::lng_passport_confirm_email(tr::now, lt_email, email),
|
||||
codeLength,
|
||||
QString(),
|
||||
submit,
|
||||
resend,
|
||||
rpl::single(QString()),
|
||||
|
||||
@@ -78,6 +78,7 @@ private:
|
||||
object_ptr<Ui::BoxContent> VerifyPhoneBox(
|
||||
const QString &phone,
|
||||
int codeLength,
|
||||
const QString &openUrl,
|
||||
Fn<void(QString code)> submit,
|
||||
rpl::producer<QString> call,
|
||||
rpl::producer<QString> error);
|
||||
|
||||
@@ -80,7 +80,8 @@ std::unique_ptr<base::Platform::DBus::ServiceWatcher> CreateServiceWatcher() {
|
||||
try {
|
||||
return ranges::contains(
|
||||
base::Platform::DBus::ListActivatableNames(connection),
|
||||
Glib::ustring(std::string(kService)));
|
||||
std::string(kService),
|
||||
&Glib::ustring::raw);
|
||||
} catch (...) {
|
||||
// avoid service restart loop in sandboxed environments
|
||||
return true;
|
||||
@@ -129,9 +130,11 @@ void StartServiceAsync(Fn<void()> callback) {
|
||||
};
|
||||
|
||||
const auto errorName =
|
||||
Gio::DBus::ErrorUtils::get_remote_error(e);
|
||||
Gio::DBus::ErrorUtils::get_remote_error(e).raw();
|
||||
|
||||
if (!ranges::contains(NotSupportedErrors, errorName)) {
|
||||
if (!ranges::contains(
|
||||
NotSupportedErrors,
|
||||
errorName)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -166,7 +169,8 @@ bool GetServiceRegistered() {
|
||||
try {
|
||||
return ranges::contains(
|
||||
DBus::ListActivatableNames(connection),
|
||||
Glib::ustring(std::string(kService)));
|
||||
std::string(kService),
|
||||
&Glib::ustring::raw);
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
@@ -383,12 +387,12 @@ bool NotificationData::init(
|
||||
const QString &msg,
|
||||
Window::Notifications::Manager::DisplayOptions options) {
|
||||
if (_application) {
|
||||
_notification = Gio::Notification::create(title.toStdString());
|
||||
|
||||
_notification->set_body(
|
||||
_notification = Gio::Notification::create(
|
||||
subtitle.isEmpty()
|
||||
? msg.toStdString()
|
||||
: u"%1\n%2"_q.arg(subtitle, msg).toStdString());
|
||||
? title.toStdString()
|
||||
: subtitle.toStdString() + " (" + title.toStdString() + ')');
|
||||
|
||||
_notification->set_body(msg.toStdString());
|
||||
|
||||
_notification->set_icon(
|
||||
Gio::ThemedIcon::create(base::IconName().toStdString()));
|
||||
@@ -498,19 +502,22 @@ bool NotificationData::init(
|
||||
});
|
||||
};
|
||||
|
||||
_title = title.toStdString();
|
||||
_imageKey = GetImageKey(CurrentServerInformationValue().specVersion);
|
||||
|
||||
if (capabilities.contains(u"body-markup"_q)) {
|
||||
_title = title.toStdString();
|
||||
|
||||
_body = subtitle.isEmpty()
|
||||
? msg.toHtmlEscaped().toStdString()
|
||||
: u"<b>%1</b>\n%2"_q.arg(
|
||||
subtitle.toHtmlEscaped(),
|
||||
msg.toHtmlEscaped()).toStdString();
|
||||
} else {
|
||||
_body = subtitle.isEmpty()
|
||||
? msg.toStdString()
|
||||
: u"%1\n%2"_q.arg(subtitle, msg).toStdString();
|
||||
_title = subtitle.isEmpty()
|
||||
? title.toStdString()
|
||||
: subtitle.toStdString() + " (" + title.toStdString() + ')';
|
||||
|
||||
_body = msg.toStdString();
|
||||
}
|
||||
|
||||
if (capabilities.contains("actions")) {
|
||||
@@ -529,12 +536,13 @@ bool NotificationData::init(
|
||||
_actions.push_back(
|
||||
tr::lng_notification_reply(tr::now).toStdString());
|
||||
|
||||
_notificationRepliedSignalId = _dbusConnection->signal_subscribe(
|
||||
signalEmitted,
|
||||
std::string(kService),
|
||||
std::string(kInterface),
|
||||
"NotificationReplied",
|
||||
std::string(kObjectPath));
|
||||
_notificationRepliedSignalId =
|
||||
_dbusConnection->signal_subscribe(
|
||||
signalEmitted,
|
||||
std::string(kService),
|
||||
std::string(kInterface),
|
||||
"NotificationReplied",
|
||||
std::string(kObjectPath));
|
||||
} else {
|
||||
// icon name according to https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
|
||||
_actions.push_back("mail-reply-sender");
|
||||
@@ -818,8 +826,6 @@ bool ByDefault() {
|
||||
static const auto NeededCapabilities = {
|
||||
// To show message content
|
||||
u"body"_q,
|
||||
// To make the sender name bold
|
||||
u"body-markup"_q,
|
||||
// To have buttons on notifications
|
||||
u"actions"_q,
|
||||
// To have quick reply
|
||||
@@ -892,7 +898,8 @@ void Create(Window::Notifications::System *system) {
|
||||
return;
|
||||
}
|
||||
|
||||
GetServerInformation([=](const std::optional<ServerInformation> &result) {
|
||||
GetServerInformation([=](
|
||||
const std::optional<ServerInformation> &result) {
|
||||
CurrentServerInformation = result;
|
||||
oneReady();
|
||||
});
|
||||
|
||||
@@ -264,7 +264,8 @@ void LaunchGApplication() {
|
||||
|
||||
if (ranges::contains(
|
||||
activatableNames,
|
||||
"org.freedesktop.Notifications")) {
|
||||
"org.freedesktop.Notifications",
|
||||
&Glib::ustring::raw)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1055,7 +1055,9 @@ void SetupDataStorage(
|
||||
auto pathtext = Core::App().settings().downloadPathValue(
|
||||
) | rpl::map([](const QString &text) {
|
||||
if (text.isEmpty()) {
|
||||
return tr::lng_download_path_default(tr::now);
|
||||
return Core::App().canReadDefaultDownloadPath(true)
|
||||
? tr::lng_download_path_default(tr::now)
|
||||
: tr::lng_download_path_unset(tr::now);
|
||||
} else if (text == FileDialog::Tmp()) {
|
||||
return tr::lng_download_path_temp(tr::now);
|
||||
}
|
||||
|
||||
@@ -280,22 +280,27 @@ void SetupPrivacy(
|
||||
{ &st::settingsIconOnline, kIconLightBlue },
|
||||
Key::LastSeen,
|
||||
[=] { return std::make_unique<LastSeenPrivacyController>(session); });
|
||||
add(
|
||||
tr::lng_settings_profile_photo_privacy(),
|
||||
{ &st::settingsIconAccount, kIconRed },
|
||||
Key::ProfilePhoto,
|
||||
[] { return std::make_unique<ProfilePhotoPrivacyController>(); });
|
||||
add(
|
||||
tr::lng_settings_forwards_privacy(),
|
||||
{ &st::settingsIconForward, kIconLightOrange },
|
||||
Key::Forwards,
|
||||
[=] { return std::make_unique<ForwardsPrivacyController>(
|
||||
controller); });
|
||||
add(
|
||||
tr::lng_settings_profile_photo_privacy(),
|
||||
{ &st::settingsIconAccount, kIconRed },
|
||||
Key::ProfilePhoto,
|
||||
[] { return std::make_unique<ProfilePhotoPrivacyController>(); });
|
||||
add(
|
||||
tr::lng_settings_calls(),
|
||||
{ &st::settingsIconVideoCalls, kIconGreen },
|
||||
Key::Calls,
|
||||
[] { return std::make_unique<CallsPrivacyController>(); });
|
||||
add(
|
||||
tr::lng_settings_groups_invite(),
|
||||
{ &st::settingsIconGroup, kIconDarkBlue },
|
||||
Key::Invites,
|
||||
[] { return std::make_unique<GroupsInvitePrivacyController>(); });
|
||||
AddPremiumPrivacyButton(
|
||||
controller,
|
||||
container,
|
||||
@@ -303,16 +308,11 @@ void SetupPrivacy(
|
||||
{ &st::settingsPremiumIconVoice, kIconRed },
|
||||
Key::Voices,
|
||||
[=] { return std::make_unique<VoicesPrivacyController>(session); });
|
||||
add(
|
||||
tr::lng_settings_groups_invite(),
|
||||
{ &st::settingsIconGroup, kIconDarkBlue },
|
||||
Key::Invites,
|
||||
[] { return std::make_unique<GroupsInvitePrivacyController>(); });
|
||||
|
||||
session->api().userPrivacy().reload(Api::UserPrivacy::Key::AddedByPhone);
|
||||
|
||||
AddSkip(container, st::settingsPrivacySecurityPadding);
|
||||
AddDividerText(container, tr::lng_settings_group_privacy_about());
|
||||
AddDivider(container);
|
||||
}
|
||||
|
||||
void SetupArchiveAndMute(
|
||||
@@ -865,10 +865,10 @@ void PrivacySecurity::setupContent(
|
||||
return rpl::duplicate(updateOnTick);
|
||||
};
|
||||
|
||||
SetupPrivacy(controller, content, trigger());
|
||||
SetupSecurity(controller, content, trigger(), [=](Type type) {
|
||||
_showOther.fire_copy(type);
|
||||
});
|
||||
SetupPrivacy(controller, content, trigger());
|
||||
#if !defined OS_MAC_STORE && !defined OS_WIN_STORE
|
||||
SetupSensitiveContent(controller, content, trigger());
|
||||
#else // !OS_MAC_STORE && !OS_WIN_STORE
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "ui/boxes/confirm_phone_box.h"
|
||||
|
||||
#include "core/file_utilities.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
@@ -22,10 +23,20 @@ ConfirmPhoneBox::ConfirmPhoneBox(
|
||||
QWidget*,
|
||||
const QString &phone,
|
||||
int codeLength,
|
||||
const QString &openUrl,
|
||||
std::optional<int> timeout)
|
||||
: _phone(phone)
|
||||
, _sentCodeLength(codeLength)
|
||||
, _call([this] { sendCall(); }, [this] { update(); }) {
|
||||
, _call([=] { sendCall(); }, [=] { update(); }) {
|
||||
if (!openUrl.isEmpty()) {
|
||||
_fragment.create(
|
||||
this,
|
||||
tr::lng_intro_fragment_button(),
|
||||
st::fragmentBoxButton);
|
||||
_fragment->setClickedCallback([=] { File::OpenUrl(openUrl); });
|
||||
_fragment->setTextTransform(
|
||||
Ui::RoundButton::TextTransform::NoTransform);
|
||||
}
|
||||
if (timeout) {
|
||||
_call.setStatus({ Ui::SentCodeCall::State::Waiting, *timeout });
|
||||
}
|
||||
@@ -59,7 +70,8 @@ void ConfirmPhoneBox::prepare() {
|
||||
+ _code->height()
|
||||
+ st::usernameSkip
|
||||
+ _about->height()
|
||||
+ st::usernameSkip);
|
||||
+ st::usernameSkip
|
||||
+ (_fragment ? (_fragment->height() + fragmentSkip()) : 0));
|
||||
|
||||
connect(_code, &Ui::InputField::submitted, [=] { sendCode(); });
|
||||
|
||||
@@ -132,15 +144,27 @@ void ConfirmPhoneBox::resizeEvent(QResizeEvent *e) {
|
||||
_code->height());
|
||||
_code->moveToLeft(st::usernamePadding.left(), st::usernamePadding.top());
|
||||
|
||||
_about->moveToLeft(
|
||||
st::usernamePadding.left(),
|
||||
_code->y() + _code->height() + st::usernameSkip);
|
||||
if (_fragment) {
|
||||
_fragment->setFullWidth(_code->width());
|
||||
_fragment->moveToLeft(
|
||||
(width() - _fragment->width()) / 2,
|
||||
_code->y() + _code->height() + st::usernameSkip);
|
||||
}
|
||||
|
||||
const auto aboutTop = _fragment
|
||||
? (_fragment->y() + _fragment->height() + fragmentSkip())
|
||||
: (_code->y() + _code->height() + st::usernameSkip);
|
||||
_about->moveToLeft(st::usernamePadding.left(), aboutTop);
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::setInnerFocus() {
|
||||
_code->setFocusFast();
|
||||
}
|
||||
|
||||
int ConfirmPhoneBox::fragmentSkip() const {
|
||||
return st::usernamePadding.bottom();
|
||||
}
|
||||
|
||||
rpl::producer<QString> ConfirmPhoneBox::checkRequests() const {
|
||||
return _checkRequests.events();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Ui {
|
||||
|
||||
class FlatLabel;
|
||||
class RoundButton;
|
||||
|
||||
class ConfirmPhoneBox final : public Ui::BoxContent {
|
||||
public:
|
||||
@@ -20,6 +21,7 @@ public:
|
||||
QWidget*,
|
||||
const QString &phone,
|
||||
int codeLength,
|
||||
const QString &openUrl,
|
||||
std::optional<int> timeout);
|
||||
|
||||
[[nodiscard]] rpl::producer<QString> checkRequests() const;
|
||||
@@ -40,6 +42,8 @@ private:
|
||||
void sendCall();
|
||||
void checkPhoneAndHash();
|
||||
|
||||
[[nodiscard]] int fragmentSkip() const;
|
||||
|
||||
QString getPhone() const;
|
||||
void showError(const QString &error);
|
||||
|
||||
@@ -54,6 +58,7 @@ private:
|
||||
|
||||
object_ptr<Ui::FlatLabel> _about = { nullptr };
|
||||
object_ptr<Ui::SentCodeField> _code = { nullptr };
|
||||
object_ptr<Ui::RoundButton> _fragment = { nullptr };
|
||||
|
||||
QString _error;
|
||||
Ui::SentCodeCall _call;
|
||||
|
||||
@@ -262,7 +262,7 @@ void GroupCallUserpics::validateCache(Userpic &userpic) {
|
||||
{
|
||||
auto p = QPainter(&userpic.cache);
|
||||
const auto skip = (kWideScale - 1) / 2 * size;
|
||||
p.drawImage(skip, skip, userpic.data.userpic);
|
||||
p.drawImage(QRect(skip, skip, size, size), userpic.data.userpic);
|
||||
|
||||
if (userpic.cacheMasked) {
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
|
||||
@@ -91,7 +91,6 @@ void CameraBox(
|
||||
},
|
||||
std::move(callback),
|
||||
track->frame(FrameRequest()).mirrored(true, false));
|
||||
box->closeBox();
|
||||
};
|
||||
|
||||
box->setTitle(tr::lng_profile_camera_title());
|
||||
@@ -208,13 +207,13 @@ void UserpicButton::prepare() {
|
||||
prepareUserpicPixmap();
|
||||
}
|
||||
setClickHandlerByRole();
|
||||
}
|
||||
|
||||
if (_role == Role::ChangePhoto) {
|
||||
chosenImages(
|
||||
) | rpl::start_with_next([=](ChosenImage &&chosen) {
|
||||
showCustom(std::move(chosen.image));
|
||||
}, lifetime());
|
||||
}
|
||||
void UserpicButton::showCustomOnChosen() {
|
||||
chosenImages(
|
||||
) | rpl::start_with_next([=](ChosenImage &&chosen) {
|
||||
showCustom(std::move(chosen.image));
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void UserpicButton::requestSuggestAvailability() {
|
||||
@@ -274,10 +273,12 @@ void UserpicButton::choosePhotoLocally() {
|
||||
const auto user = _peer ? _peer->asUser() : nullptr;
|
||||
const auto name = (user && !user->firstName.isEmpty())
|
||||
? user->firstName
|
||||
: _peer->name();
|
||||
: _peer
|
||||
? _peer->name()
|
||||
: QString();
|
||||
const auto phrase = (type == ChosenType::Suggest)
|
||||
? &tr::lng_profile_suggest_sure
|
||||
: (_peer->isUser() && !_peer->isSelf())
|
||||
: (user && !user->isSelf())
|
||||
? &tr::lng_profile_set_personal_sure
|
||||
: nullptr;
|
||||
PrepareProfilePhotoFromFile(
|
||||
|
||||
@@ -100,6 +100,7 @@ public:
|
||||
|
||||
void showCustom(QImage &&image);
|
||||
void showSource(Source source);
|
||||
void showCustomOnChosen();
|
||||
|
||||
void overrideHasPersonalPhoto(bool has);
|
||||
[[nodiscard]] rpl::producer<> resetPersonalRequests() const;
|
||||
|
||||
@@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "countries/countries_instance.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QtCore/QLocale>
|
||||
#include <locale>
|
||||
#include <sstream>
|
||||
|
||||
@@ -134,6 +134,12 @@ void PhonePartInput::correctValue(
|
||||
int wasCursor,
|
||||
QString &now,
|
||||
int &nowCursor) {
|
||||
if (!now.isEmpty() && (_lastDigits != now)) {
|
||||
_lastDigits = now;
|
||||
_lastDigits.replace(TextUtilities::RegExpDigitsExclude(), QString());
|
||||
updatePattern(_groupsCallback(_code + _lastDigits));
|
||||
}
|
||||
|
||||
QString newText;
|
||||
int oldPos(nowCursor), newPos(-1), oldLen(now.length()), digitCount = 0;
|
||||
for (int i = 0; i < oldLen; ++i) {
|
||||
@@ -212,21 +218,8 @@ void PhonePartInput::addedToNumber(const QString &added) {
|
||||
}
|
||||
|
||||
void PhonePartInput::chooseCode(const QString &code) {
|
||||
_pattern = _groupsCallback(code);
|
||||
if (!_pattern.isEmpty() && _pattern.at(0) == code.size()) {
|
||||
_pattern.pop_front();
|
||||
} else {
|
||||
_pattern.clear();
|
||||
}
|
||||
_additionalPlaceholder = QString();
|
||||
if (!_pattern.isEmpty()) {
|
||||
_additionalPlaceholder.reserve(20);
|
||||
for (const auto part : std::as_const(_pattern)) {
|
||||
_additionalPlaceholder.append(' ');
|
||||
_additionalPlaceholder.append(QString(part, QChar(0x2212)));
|
||||
}
|
||||
}
|
||||
setPlaceholderHidden(!_additionalPlaceholder.isEmpty());
|
||||
_code = code;
|
||||
updatePattern(_groupsCallback(_code));
|
||||
|
||||
auto wasText = getLastText();
|
||||
auto wasCursor = cursorPosition();
|
||||
@@ -239,6 +232,27 @@ void PhonePartInput::chooseCode(const QString &code) {
|
||||
update();
|
||||
}
|
||||
|
||||
void PhonePartInput::updatePattern(QVector<int> &&pattern) {
|
||||
if (_pattern == pattern) {
|
||||
return;
|
||||
}
|
||||
_pattern = std::move(pattern);
|
||||
if (!_pattern.isEmpty() && _pattern.at(0) == _code.size()) {
|
||||
_pattern.pop_front();
|
||||
} else {
|
||||
_pattern.clear();
|
||||
}
|
||||
_additionalPlaceholder = QString();
|
||||
if (!_pattern.isEmpty()) {
|
||||
_additionalPlaceholder.reserve(20);
|
||||
for (const auto &part : _pattern) {
|
||||
_additionalPlaceholder.append(' ');
|
||||
_additionalPlaceholder.append(QString(part, QChar(0x2212)));
|
||||
}
|
||||
}
|
||||
setPlaceholderHidden(!_additionalPlaceholder.isEmpty());
|
||||
}
|
||||
|
||||
UsernameInput::UsernameInput(
|
||||
QWidget *parent,
|
||||
const style::InputField &st,
|
||||
@@ -345,7 +359,7 @@ void PhoneInput::correctValue(
|
||||
QString &now,
|
||||
int &nowCursor) {
|
||||
auto digits = now;
|
||||
digits.replace(QRegularExpression("[^\\d]"), QString());
|
||||
digits.replace(TextUtilities::RegExpDigitsExclude(), QString());
|
||||
_pattern = _groupsCallback(digits);
|
||||
|
||||
QString newPlaceholder;
|
||||
|
||||
@@ -68,6 +68,10 @@ protected:
|
||||
void paintAdditionalPlaceholder(QPainter &p) override;
|
||||
|
||||
private:
|
||||
void updatePattern(QVector<int> &&pattern);
|
||||
|
||||
QString _code;
|
||||
QString _lastDigits;
|
||||
QVector<int> _pattern;
|
||||
QString _additionalPlaceholder;
|
||||
rpl::event_stream<not_null<QKeyEvent*>> _frontBackspaceEvent;
|
||||
|
||||
@@ -34,9 +34,7 @@ void SentCodeField::setChangedCallback(Fn<void()> changedCallback) {
|
||||
QString SentCodeField::getDigitsOnly() const {
|
||||
return QString(
|
||||
getLastText()
|
||||
).remove(
|
||||
QRegularExpression("[^\\d]")
|
||||
);
|
||||
).remove(TextUtilities::RegExpDigitsExclude());
|
||||
}
|
||||
|
||||
void SentCodeField::fix() {
|
||||
|
||||
@@ -956,8 +956,12 @@ OthersUnreadState OtherAccountsUnreadStateCurrent() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// In case we are logging out in the last paint for the slide animation
|
||||
// the account doesn't have the session here already.
|
||||
const auto current = active->maybeSession();
|
||||
return {
|
||||
.count = (app.unreadBadge() - active->session().data().unreadBadge()),
|
||||
.count = (app.unreadBadge()
|
||||
- (current ? current->data().unreadBadge() : 0)),
|
||||
.allMuted = allMuted,
|
||||
};
|
||||
}
|
||||
|
||||
2
Telegram/ThirdParty/libtgvoip
vendored
2
Telegram/ThirdParty/libtgvoip
vendored
Submodule Telegram/ThirdParty/libtgvoip updated: 0ffe2e51bf...7c46f4c23e
@@ -4,6 +4,7 @@
|
||||
#define MyAppURL "https://desktop.telegram.org"
|
||||
#define MyAppExeName "Telegram.exe"
|
||||
#define MyAppId "53F49750-6209-4FBF-9CA8-7A333C87D1ED"
|
||||
#define CurrentYear GetDateTimeString('yyyy','','')
|
||||
|
||||
[Setup]
|
||||
; NOTE: The value of AppId uniquely identifies this application.
|
||||
@@ -12,6 +13,7 @@
|
||||
AppId={{{#MyAppId}}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppCopyright={#MyAppPublisher} 2014-{#CurrentYear}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
AppPublisherURL={#MyAppURL}
|
||||
AppSupportURL={#MyAppURL}
|
||||
@@ -33,27 +35,29 @@ DisableDirPage=no
|
||||
DisableProgramGroupPage=no
|
||||
|
||||
#if MyBuildTarget == "win64"
|
||||
ArchitecturesAllowed="x64 arm64"
|
||||
ArchitecturesInstallIn64BitMode="x64 arm64"
|
||||
OutputBaseFilename=tsetup-x64.{#MyAppVersionFull}
|
||||
#define ArchModulesFolder "x64"
|
||||
ArchitecturesAllowed="x64 arm64"
|
||||
ArchitecturesInstallIn64BitMode="x64 arm64"
|
||||
OutputBaseFilename=tsetup-x64.{#MyAppVersionFull}
|
||||
#define ArchModulesFolder "x64"
|
||||
AppVerName={#MyAppName} {#MyAppVersion} 64bit
|
||||
#else
|
||||
OutputBaseFilename=tsetup.{#MyAppVersionFull}
|
||||
#define ArchModulesFolder "x86"
|
||||
OutputBaseFilename=tsetup.{#MyAppVersionFull}
|
||||
#define ArchModulesFolder "x86"
|
||||
AppVerName={#MyAppName} {#MyAppVersion} 32bit
|
||||
#endif
|
||||
|
||||
#define ModulesFolder "modules\" + ArchModulesFolder
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
Name: "it"; MessagesFile: "compiler:Languages\Italian.isl"
|
||||
Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl"
|
||||
Name: "de"; MessagesFile: "compiler:Languages\German.isl"
|
||||
Name: "nl"; MessagesFile: "compiler:Languages\Dutch.isl"
|
||||
Name: "pt_BR"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl"
|
||||
Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl"
|
||||
Name: "fr"; MessagesFile: "compiler:Languages\French.isl"
|
||||
Name: "ua"; MessagesFile: "compiler:Languages\Ukrainian.isl"
|
||||
Name: "it"; MessagesFile: "compiler:Languages\Italian.isl"
|
||||
Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl"
|
||||
Name: "de"; MessagesFile: "compiler:Languages\German.isl"
|
||||
Name: "nl"; MessagesFile: "compiler:Languages\Dutch.isl"
|
||||
Name: "pt_BR"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl"
|
||||
Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl"
|
||||
Name: "fr"; MessagesFile: "compiler:Languages\French.isl"
|
||||
Name: "ua"; MessagesFile: "compiler:Languages\Ukrainian.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
AppVersion 4004002
|
||||
AppVersion 4004003
|
||||
AppVersionStrMajor 4.4
|
||||
AppVersionStrSmall 4.4.2
|
||||
AppVersionStr 4.4.2
|
||||
AppVersionStrSmall 4.4.3
|
||||
AppVersionStr 4.4.3
|
||||
BetaChannel 1
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 4.4.2.beta
|
||||
AppVersionOriginal 4.4.3.beta
|
||||
|
||||
Submodule Telegram/lib_base updated: 1df4417b0c...117b8a248d
Submodule Telegram/lib_ui updated: 28fd4eea95...3fea35ff19
@@ -1,3 +1,9 @@
|
||||
4.4.3 beta (29.12.22)
|
||||
|
||||
- Support for anonymous numbers from the Fragment.com platform.
|
||||
- Fix a crash in own profile photo updating.
|
||||
- Bug fixes and other minor improvements.
|
||||
|
||||
4.4.2 beta (28.12.22)
|
||||
|
||||
- Send photos and video files hidden by a spoiler effect.
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<url type="homepage">https://desktop.telegram.org/</url>
|
||||
<url type="bugtracker">https://github.com/telegramdesktop/tdesktop/issues</url>
|
||||
<url type="translate">https://translations.telegram.org/</url>
|
||||
<url type="contribute">https://github.com/telegramdesktop/tdesktop/blob/dev/.github/CONTRIBUTING.md</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/docs/assets/preview.png</image>
|
||||
@@ -43,6 +44,15 @@
|
||||
<keyword>sms</keyword>
|
||||
<keyword>im</keyword>
|
||||
</keywords>
|
||||
<requires>
|
||||
<display_length compare="ge">medium</display_length>
|
||||
<internet>always</internet>
|
||||
</requires>
|
||||
<supports>
|
||||
<control>pointing</control>
|
||||
<control>keyboard</control>
|
||||
<control>touch</control>
|
||||
</supports>
|
||||
<content_rating type="oars-1.1">
|
||||
<content_attribute id="violence-cartoon">none</content_attribute>
|
||||
<content_attribute id="violence-fantasy">none</content_attribute>
|
||||
|
||||
Reference in New Issue
Block a user