Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0077d98f0 | ||
|
|
b5bc7a22af | ||
|
|
e60311811b | ||
|
|
8700c1b08f | ||
|
|
d8b51670e7 | ||
|
|
68c2f563c6 | ||
|
|
bf775cb4ca | ||
|
|
5c4b81434e | ||
|
|
cd1c7c56d3 | ||
|
|
427ceb9a9a | ||
|
|
2a110f0d3e | ||
|
|
d0ed75f3b5 |
@@ -1567,7 +1567,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passport_address_agreement" = "Tenancy agreement";
|
||||
"lng_passport_address_agreement_upload" = "Upload a scan of your tenancy agreement";
|
||||
"lng_passport_address_registration" = "Passport registration";
|
||||
"lng_passport_address_registration_upload" = "Upload a scan of your passport registration";
|
||||
"lng_passport_address_registration_upload" = "Upload a scan of your passport registration page";
|
||||
"lng_passport_address_temporary" = "Temporary registration";
|
||||
"lng_passport_address_temporary_upload" = "Upload a scan of your temporary registration";
|
||||
"lng_passport_address_about" = "To confirm your address, please upload a scan or photo of the selected document (all pages).";
|
||||
@@ -1594,12 +1594,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passport_upload_selfie" = "Upload selfie";
|
||||
"lng_passport_front_side_title" = "Front side";
|
||||
"lng_passport_front_side_name" = "Scan";
|
||||
"lng_passport_front_side_description" = "Upload front side of your document.";
|
||||
"lng_passport_upload_front_side" = "Upload front side scan";
|
||||
"lng_passport_front_side_description" = "Upload the front side of your document.";
|
||||
"lng_passport_upload_front_side" = "Upload a scan of the front side";
|
||||
"lng_passport_reverse_side_title" = "Reverse side";
|
||||
"lng_passport_reverse_side_name" = "Scan";
|
||||
"lng_passport_reverse_side_description" = "Upload reverse side of your document.";
|
||||
"lng_passport_upload_reverse_side" = "Upload reverse side scan";
|
||||
"lng_passport_reverse_side_description" = "Upload the reverse side of your document.";
|
||||
"lng_passport_upload_reverse_side" = "Upload a scan of the reverse side";
|
||||
"lng_passport_personal_details" = "Personal details";
|
||||
"lng_passport_personal_details_enter" = "Enter your personal details";
|
||||
"lng_passport_choose_image" = "Choose scan image";
|
||||
@@ -1648,10 +1648,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passport_stop" = "Stop";
|
||||
"lng_passport_restart_sure" = "An unexpected error has occurred. Perhaps some changes were made from a different Telegram application. Would you like to restart this authorization?";
|
||||
"lng_passport_restart" = "Restart";
|
||||
"lng_passport_error_too_large" = "This file is too large.";
|
||||
"lng_passport_error_bad_size" = "This image has bad dimensions.";
|
||||
"lng_passport_error_too_large" = "Sorry, this file is too large.";
|
||||
"lng_passport_error_bad_size" = "Sorry, this image has wrong dimensions.";
|
||||
"lng_passport_error_cant_read" = "Can't read this file. Please choose an image.";
|
||||
"lng_passport_bad_name" = "Use latin characters only.";
|
||||
"lng_passport_bad_name" = "Please use latin characters only.";
|
||||
|
||||
// Wnd specific
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="1.3.4.0" />
|
||||
Version="1.3.7.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,3,4,0
|
||||
PRODUCTVERSION 1,3,4,0
|
||||
FILEVERSION 1,3,7,0
|
||||
PRODUCTVERSION 1,3,7,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -52,10 +52,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "1.3.4.0"
|
||||
VALUE "FileVersion", "1.3.7.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.3.4.0"
|
||||
VALUE "ProductVersion", "1.3.7.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,3,4,0
|
||||
PRODUCTVERSION 1,3,4,0
|
||||
FILEVERSION 1,3,7,0
|
||||
PRODUCTVERSION 1,3,7,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -43,10 +43,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "1.3.4.0"
|
||||
VALUE "FileVersion", "1.3.7.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.3.4.0"
|
||||
VALUE "ProductVersion", "1.3.7.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -2055,10 +2055,21 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
if (!textWithTags.tags.isEmpty()) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_entities;
|
||||
}
|
||||
auto entities = TextUtilities::EntitiesToMTP(ConvertTextTagsToEntities(textWithTags.tags), TextUtilities::ConvertOption::SkipLocal);
|
||||
auto entities = TextUtilities::EntitiesToMTP(
|
||||
ConvertTextTagsToEntities(textWithTags.tags),
|
||||
TextUtilities::ConvertOption::SkipLocal);
|
||||
|
||||
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(MTP_flags(flags), MTP_int(cloudDraft->msgId), history->peer->input, MTP_string(textWithTags.text), entities)).done([this, history](const MTPBool &result, mtpRequestId requestId) {
|
||||
if (auto cloudDraft = history->cloudDraft()) {
|
||||
history->setSentDraftText(textWithTags.text);
|
||||
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
|
||||
MTP_flags(flags),
|
||||
MTP_int(cloudDraft->msgId),
|
||||
history->peer->input,
|
||||
MTP_string(textWithTags.text),
|
||||
entities
|
||||
)).done([=](const MTPBool &result, mtpRequestId requestId) {
|
||||
history->clearSentDraftText();
|
||||
|
||||
if (const auto cloudDraft = history->cloudDraft()) {
|
||||
if (cloudDraft->saveRequestId == requestId) {
|
||||
cloudDraft->saveRequestId = 0;
|
||||
history->draftSavedToCloud();
|
||||
@@ -2069,8 +2080,10 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
_draftsSaveRequestIds.erase(history);
|
||||
checkQuitPreventFinished();
|
||||
}
|
||||
}).fail([this, history](const RPCError &error, mtpRequestId requestId) {
|
||||
if (auto cloudDraft = history->cloudDraft()) {
|
||||
}).fail([=](const RPCError &error, mtpRequestId requestId) {
|
||||
history->clearSentDraftText();
|
||||
|
||||
if (const auto cloudDraft = history->cloudDraft()) {
|
||||
if (cloudDraft->saveRequestId == requestId) {
|
||||
history->clearCloudDraft();
|
||||
}
|
||||
|
||||
@@ -50,8 +50,7 @@ namespace {
|
||||
|
||||
UserData *self = nullptr;
|
||||
|
||||
using PeersData = QHash<PeerId, PeerData*>;
|
||||
PeersData peersData;
|
||||
std::unordered_map<PeerId, std::unique_ptr<PeerData>> peersData;
|
||||
|
||||
using LocationsData = QHash<LocationCoords, LocationData*>;
|
||||
LocationsData locationsData;
|
||||
@@ -747,7 +746,7 @@ namespace App {
|
||||
} else if (chat->version <= d.vversion.v && chat->count > 0) {
|
||||
chat->version = d.vversion.v;
|
||||
auto canEdit = chat->canEdit();
|
||||
UserData *user = App::userLoaded(d.vuser_id.v);
|
||||
const auto user = App::userLoaded(d.vuser_id.v);
|
||||
if (user) {
|
||||
if (chat->participants.empty()) {
|
||||
if (chat->count > 0) {
|
||||
@@ -1074,40 +1073,43 @@ namespace App {
|
||||
}
|
||||
|
||||
PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) {
|
||||
if (!id) return nullptr;
|
||||
if (!id) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto i = peersData.constFind(id);
|
||||
auto i = peersData.find(id);
|
||||
if (i == peersData.cend()) {
|
||||
PeerData *newData = nullptr;
|
||||
if (peerIsUser(id)) {
|
||||
newData = new UserData(id);
|
||||
} else if (peerIsChat(id)) {
|
||||
newData = new ChatData(id);
|
||||
} else if (peerIsChannel(id)) {
|
||||
newData = new ChannelData(id);
|
||||
}
|
||||
Assert(newData != nullptr);
|
||||
auto newData = [&]() -> std::unique_ptr<PeerData> {
|
||||
if (peerIsUser(id)) {
|
||||
return std::make_unique<UserData>(id);
|
||||
} else if (peerIsChat(id)) {
|
||||
return std::make_unique<ChatData>(id);
|
||||
} else if (peerIsChannel(id)) {
|
||||
return std::make_unique<ChannelData>(id);
|
||||
}
|
||||
Unexpected("Peer id type.");
|
||||
}();
|
||||
|
||||
newData->input = MTPinputPeer(MTP_inputPeerEmpty());
|
||||
i = peersData.insert(id, newData);
|
||||
i = peersData.emplace(id, std::move(newData)).first;
|
||||
}
|
||||
switch (restriction) {
|
||||
case PeerData::MinimalLoaded: {
|
||||
if (i.value()->loadedStatus == PeerData::NotLoaded) {
|
||||
if (i->second->loadedStatus == PeerData::NotLoaded) {
|
||||
return nullptr;
|
||||
}
|
||||
} break;
|
||||
case PeerData::FullLoaded: {
|
||||
if (i.value()->loadedStatus != PeerData::FullLoaded) {
|
||||
if (i->second->loadedStatus != PeerData::FullLoaded) {
|
||||
return nullptr;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return i.value();
|
||||
return i->second.get();
|
||||
}
|
||||
|
||||
void enumerateUsers(Fn<void(not_null<UserData*>)> action) {
|
||||
for_const (const auto peer, peersData) {
|
||||
for (const auto &[peerId, peer] : peersData) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
action(user);
|
||||
}
|
||||
@@ -1116,9 +1118,9 @@ namespace App {
|
||||
|
||||
void enumerateChatsChannels(
|
||||
Fn<void(not_null<PeerData*>)> action) {
|
||||
for_const (const auto peer, peersData) {
|
||||
for (const auto &[peerId, peer] : peersData) {
|
||||
if (!peer->isUser()) {
|
||||
action(peer);
|
||||
action(peer.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1128,10 +1130,10 @@ namespace App {
|
||||
}
|
||||
|
||||
PeerData *peerByName(const QString &username) {
|
||||
QString uname(username.trimmed());
|
||||
for_const (PeerData *peer, peersData) {
|
||||
const auto uname = username.trimmed();
|
||||
for (const auto &[peerId, peer] : peersData) {
|
||||
if (!peer->userName().compare(uname, Qt::CaseInsensitive)) {
|
||||
return peer;
|
||||
return peer.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -1246,24 +1248,16 @@ namespace App {
|
||||
void historyClearMsgs() {
|
||||
::dependentItems.clear();
|
||||
|
||||
QVector<HistoryItem*> toDelete;
|
||||
for_const (auto item, msgsData) {
|
||||
if (!item->mainView()) {
|
||||
toDelete.push_back(item);
|
||||
}
|
||||
}
|
||||
for_const (auto &chMsgsData, channelMsgsData) {
|
||||
for_const (auto item, chMsgsData) {
|
||||
if (!item->mainView()) {
|
||||
toDelete.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
msgsData.clear();
|
||||
channelMsgsData.clear();
|
||||
for_const (auto item, toDelete) {
|
||||
const auto oldData = base::take(msgsData);
|
||||
const auto oldChannelData = base::take(channelMsgsData);
|
||||
for (const auto item : oldData) {
|
||||
delete item;
|
||||
}
|
||||
for (const auto &data : oldChannelData) {
|
||||
for (const auto item : data) {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
clearMousedItems();
|
||||
}
|
||||
@@ -1275,10 +1269,7 @@ namespace App {
|
||||
cSetSavedPeersByTime(SavedPeersByTime());
|
||||
cSetRecentInlineBots(RecentInlineBots());
|
||||
|
||||
for_const (auto peer, ::peersData) {
|
||||
delete peer;
|
||||
}
|
||||
::peersData.clear();
|
||||
peersData.clear();
|
||||
|
||||
if (AuthSession::Exists()) {
|
||||
Auth().api().clearWebPageRequests();
|
||||
|
||||
@@ -21,6 +21,10 @@ constexpr auto kForeverHours = 24 * 365;
|
||||
|
||||
} // namespace
|
||||
|
||||
MuteSettingsBox::MuteSettingsBox(QWidget *parent, not_null<PeerData*> peer)
|
||||
: _peer(peer) {
|
||||
}
|
||||
|
||||
void MuteSettingsBox::prepare() {
|
||||
setTitle(langFactory(lng_disable_notifications_from_tray));
|
||||
auto y = 0;
|
||||
@@ -67,15 +71,25 @@ void MuteSettingsBox::prepare() {
|
||||
- st::boxOptionListSkip
|
||||
+ st::defaultCheckbox.margin.bottom();
|
||||
|
||||
addButton(langFactory(lng_box_ok), [this, group] {
|
||||
auto muteForSeconds = group->value() * 3600;
|
||||
_save = [=] {
|
||||
const auto muteForSeconds = group->value() * 3600;
|
||||
Auth().data().updateNotifySettings(
|
||||
_peer,
|
||||
muteForSeconds);
|
||||
closeBox();
|
||||
});
|
||||
};
|
||||
addButton(langFactory(lng_box_ok), _save);
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWidth, y);
|
||||
}
|
||||
|
||||
void MuteSettingsBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
if (_save) {
|
||||
_save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vi: ts=4 tw=80
|
||||
|
||||
@@ -13,17 +13,17 @@ Copyright (C) 2017, Nicholas Guriev <guriev-ns@ya.ru>
|
||||
* turning off notifications from a chat. The widget is opened by a context menu
|
||||
* in the left list of dialogues. */
|
||||
class MuteSettingsBox : public BoxContent {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MuteSettingsBox(QWidget *parent, not_null<PeerData*> peer);
|
||||
|
||||
public:
|
||||
MuteSettingsBox(QWidget *parent, not_null<PeerData*> peer)
|
||||
: _peer(peer) {
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
not_null<PeerData*> _peer;
|
||||
Fn<void()> _save;
|
||||
|
||||
};
|
||||
// vi: ts=4 tw=80
|
||||
|
||||
@@ -82,9 +82,6 @@ enum {
|
||||
MaxMessageSize = 4096,
|
||||
|
||||
WriteMapTimeout = 1000,
|
||||
SaveDraftTimeout = 1000, // save draft after 1 secs of not changing text
|
||||
SaveDraftAnywayTimeout = 5000, // or save anyway each 5 secs
|
||||
SaveCloudDraftIdleTimeout = 14000, // save draft to the cloud after 14 more seconds
|
||||
|
||||
SetOnlineAfterActivity = 30, // user with hidden last seen stays online for such amount of seconds in the interface
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#define BETA_VERSION_MACRO (0ULL)
|
||||
|
||||
constexpr int AppVersion = 1003004;
|
||||
constexpr str_const AppVersionStr = "1.3.4";
|
||||
constexpr bool AppAlphaVersion = true;
|
||||
constexpr int AppVersion = 1003007;
|
||||
constexpr str_const AppVersionStr = "1.3.7";
|
||||
constexpr bool AppAlphaVersion = false;
|
||||
constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO;
|
||||
|
||||
@@ -52,6 +52,9 @@ void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft) {
|
||||
? TextUtilities::EntitiesFromMTP(draft.ventities.v)
|
||||
: EntitiesInText())
|
||||
};
|
||||
if (history->skipCloudDraft(textWithTags.text, draft.vdate.v)) {
|
||||
return;
|
||||
}
|
||||
auto replyTo = draft.has_reply_to_msg_id() ? draft.vreply_to_msg_id.v : MsgId(0);
|
||||
auto cloudDraft = std::make_unique<Draft>(textWithTags, replyTo, MessageCursor(QFIXED_MAX, QFIXED_MAX, QFIXED_MAX), draft.is_no_webpage());
|
||||
cloudDraft->date = draft.vdate.v;
|
||||
|
||||
@@ -51,6 +51,7 @@ constexpr auto kStatusShowClientsideChooseContact = 6000;
|
||||
constexpr auto kStatusShowClientsidePlayGame = 10000;
|
||||
constexpr auto kSetMyActionForMs = 10000;
|
||||
constexpr auto kNewBlockEachMessage = 50;
|
||||
constexpr auto kSkipCloudDraftsFor = TimeId(3);
|
||||
|
||||
void checkForSwitchInlineButton(HistoryItem *item) {
|
||||
if (item->out() || !item->hasSwitchInlineButton()) {
|
||||
@@ -98,8 +99,10 @@ not_null<History*> Histories::findOrInsert(PeerId peerId) {
|
||||
}
|
||||
|
||||
void Histories::clear() {
|
||||
for (const auto &[peerId, history] : _map) {
|
||||
history->unloadBlocks();
|
||||
}
|
||||
App::historyClearMsgs();
|
||||
|
||||
_map.clear();
|
||||
|
||||
_unreadFull = _unreadMuted = 0;
|
||||
@@ -405,6 +408,24 @@ Data::Draft *History::createCloudDraft(Data::Draft *fromDraft) {
|
||||
return cloudDraft();
|
||||
}
|
||||
|
||||
bool History::skipCloudDraft(const QString &text, TimeId date) const {
|
||||
if (_lastSentDraftText && *_lastSentDraftText == text) {
|
||||
return true;
|
||||
} else if (date <= _lastSentDraftTime + kSkipCloudDraftsFor) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void History::setSentDraftText(const QString &text) {
|
||||
_lastSentDraftText = text;
|
||||
}
|
||||
|
||||
void History::clearSentDraftText() {
|
||||
_lastSentDraftText = base::none;
|
||||
accumulate_max(_lastSentDraftTime, unixtime());
|
||||
}
|
||||
|
||||
void History::setEditDraft(std::unique_ptr<Data::Draft> &&draft) {
|
||||
_editDraft = std::move(draft);
|
||||
}
|
||||
|
||||
@@ -304,6 +304,9 @@ public:
|
||||
void createLocalDraftFromCloud();
|
||||
void setCloudDraft(std::unique_ptr<Data::Draft> &&draft);
|
||||
Data::Draft *createCloudDraft(Data::Draft *fromDraft);
|
||||
bool skipCloudDraft(const QString &text, TimeId date) const;
|
||||
void setSentDraftText(const QString &text);
|
||||
void clearSentDraftText();
|
||||
void setEditDraft(std::unique_ptr<Data::Draft> &&draft);
|
||||
void clearLocalDraft();
|
||||
void clearCloudDraft();
|
||||
@@ -501,6 +504,8 @@ private:
|
||||
|
||||
std::unique_ptr<Data::Draft> _localDraft, _cloudDraft;
|
||||
std::unique_ptr<Data::Draft> _editDraft;
|
||||
base::optional<QString> _lastSentDraftText;
|
||||
TimeId _lastSentDraftTime = 0;
|
||||
MessageIdsList _forwardDraft;
|
||||
|
||||
using TypingUsers = QMap<UserData*, TimeMs>;
|
||||
|
||||
@@ -91,6 +91,9 @@ constexpr auto kShowMembersDropdownTimeoutMs = 300;
|
||||
constexpr auto kDisplayEditTimeWarningMs = 300 * 1000;
|
||||
constexpr auto kFullDayInMs = 86400 * 1000;
|
||||
constexpr auto kCancelTypingActionTimeout = TimeMs(5000);
|
||||
constexpr auto kSaveDraftTimeout = 1000;
|
||||
constexpr auto kSaveDraftAnywayTimeout = 5000;
|
||||
constexpr auto kSaveCloudDraftIdleTimeout = 14000;
|
||||
|
||||
ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() {
|
||||
return [](ChannelData *channel, MsgId msgId) {
|
||||
@@ -1192,9 +1195,9 @@ void HistoryWidget::onDraftSave(bool delayed) {
|
||||
auto ms = getms();
|
||||
if (!_saveDraftStart) {
|
||||
_saveDraftStart = ms;
|
||||
return _saveDraftTimer.start(SaveDraftTimeout);
|
||||
} else if (ms - _saveDraftStart < SaveDraftAnywayTimeout) {
|
||||
return _saveDraftTimer.start(SaveDraftTimeout);
|
||||
return _saveDraftTimer.start(kSaveDraftTimeout);
|
||||
} else if (ms - _saveDraftStart < kSaveDraftAnywayTimeout) {
|
||||
return _saveDraftTimer.start(kSaveDraftTimeout);
|
||||
}
|
||||
}
|
||||
writeDrafts(nullptr, nullptr);
|
||||
@@ -1275,7 +1278,7 @@ void HistoryWidget::writeDrafts(Data::Draft **localDraft, Data::Draft **editDraf
|
||||
}
|
||||
|
||||
if (!_editMsgId && !_inlineBot) {
|
||||
_saveCloudDraftTimer.start(SaveCloudDraftIdleTimeout);
|
||||
_saveCloudDraftTimer.start(kSaveCloudDraftIdleTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -494,8 +494,9 @@ void TopBarWidget::updateControlsGeometry() {
|
||||
buttonsWidth += buttonsLeft + st::topBarActionSkip * 3;
|
||||
|
||||
auto widthLeft = qMin(width() - buttonsWidth, -2 * st::defaultActiveButton.width);
|
||||
_forward->setFullWidth(-(widthLeft / 2));
|
||||
_delete->setFullWidth(-(widthLeft / 2));
|
||||
auto buttonFullWidth = qMin(-(widthLeft / 2), 0);
|
||||
_forward->setFullWidth(buttonFullWidth);
|
||||
_delete->setFullWidth(buttonFullWidth);
|
||||
|
||||
selectedButtonsTop += (height() - _forward->height()) / 2;
|
||||
|
||||
|
||||
@@ -69,9 +69,9 @@ public:
|
||||
|
||||
void closeMain() {
|
||||
QMutexLocker lock(_logsMutex(LogDataMain));
|
||||
if (files[LogDataMain]) {
|
||||
streams[LogDataMain].setDevice(0);
|
||||
files[LogDataMain]->close();
|
||||
const auto file = files[LogDataMain].get();
|
||||
if (file && file->isOpen()) {
|
||||
file->close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,11 +80,12 @@ public:
|
||||
}
|
||||
|
||||
QString full() {
|
||||
if (!streams[LogDataMain].device()) {
|
||||
const auto file = files[LogDataMain].get();
|
||||
if (!!file || !file->isOpen()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QFile out(files[LogDataMain]->fileName());
|
||||
QFile out(file->fileName());
|
||||
if (out.open(QIODevice::ReadOnly)) {
|
||||
return QString::fromUtf8(out.readAll());
|
||||
}
|
||||
@@ -93,27 +94,29 @@ public:
|
||||
|
||||
void write(LogDataType type, const QString &msg) {
|
||||
QMutexLocker lock(_logsMutex(type));
|
||||
if (type != LogDataMain) reopenDebug();
|
||||
if (!streams[type].device()) return;
|
||||
|
||||
streams[type] << msg;
|
||||
streams[type].flush();
|
||||
if (type != LogDataMain) {
|
||||
reopenDebug();
|
||||
}
|
||||
const auto file = files[type].get();
|
||||
if (!file || !file->isOpen()) {
|
||||
return;
|
||||
}
|
||||
file->write(msg.toUtf8());
|
||||
file->flush();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<QFile> files[LogDataCount];
|
||||
QTextStream streams[LogDataCount];
|
||||
|
||||
int32 part = -1;
|
||||
|
||||
bool reopen(LogDataType type, int32 dayIndex, const QString &postfix) {
|
||||
if (streams[type].device()) {
|
||||
if (files[type] && files[type]->isOpen()) {
|
||||
if (type == LogDataMain) {
|
||||
if (!postfix.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
streams[type].setDevice(0);
|
||||
files[type]->close();
|
||||
}
|
||||
}
|
||||
@@ -134,8 +137,6 @@ private:
|
||||
}
|
||||
if (to->open(mode | QIODevice::Append)) {
|
||||
std::swap(files[type], to);
|
||||
streams[type].setDevice(files[type].get());
|
||||
streams[type].setCodec("UTF-8");
|
||||
LOG(("Moved logging from '%1' to '%2'!").arg(to->fileName()).arg(files[type]->fileName()));
|
||||
to->remove();
|
||||
|
||||
@@ -192,17 +193,14 @@ private:
|
||||
}
|
||||
}
|
||||
if (files[type]->open(mode)) {
|
||||
streams[type].setDevice(files[type].get());
|
||||
streams[type].setCodec("UTF-8");
|
||||
|
||||
if (type != LogDataMain) {
|
||||
streams[type] << ((mode & QIODevice::Append)
|
||||
files[type]->write(((mode & QIODevice::Append)
|
||||
? qsl("\
|
||||
----------------------------------------------------------------\n\
|
||||
NEW LOGGING INSTANCE STARTED!!!\n\
|
||||
----------------------------------------------------------------\n")
|
||||
: qsl("%1\n").arg(dayIndex));
|
||||
streams[type].flush();
|
||||
: qsl("%1\n").arg(dayIndex)).toUtf8());
|
||||
files[type]->flush();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -34,6 +34,7 @@ passportErrorLabel: FlatLabel(passportPasswordLabel) {
|
||||
textFg: boxTextFgError;
|
||||
}
|
||||
passportVerifyErrorLabel: FlatLabel(passportErrorLabel) {
|
||||
minWidth: 128px;
|
||||
align: align(topleft);
|
||||
}
|
||||
|
||||
@@ -169,10 +170,11 @@ passportDetailsField: InputField(defaultInputField) {
|
||||
font: normalFont;
|
||||
}
|
||||
passportDetailsDateField: InputField(passportDetailsField) {
|
||||
textMargins: margins(2px, 8px, 2px, 0px);
|
||||
border: 0px;
|
||||
borderActive: 0px;
|
||||
heightMin: 30px;
|
||||
placeholderFont: font(semibold 14px);
|
||||
placeholderFont: semiboldFont;
|
||||
placeholderFgActive: placeholderFgActive;
|
||||
}
|
||||
passportDetailsSeparator: FlatLabel(passportPasswordLabelBold) {
|
||||
@@ -189,7 +191,7 @@ passportDetailsFieldLeft: 116px;
|
||||
passportDetailsFieldTop: 2px;
|
||||
passportDetailsFieldSkipMin: 12px;
|
||||
passportDetailsSkip: 30px;
|
||||
passportDetailsGenderSkip: 30px;
|
||||
passportDetailsGenderSkip: 20px;
|
||||
|
||||
passportRequestTypeSkip: 16px;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ EditDocumentScheme GetDocumentScheme(
|
||||
if (value.isEmpty() || value.size() > kMaxNameSize) {
|
||||
return QString();
|
||||
} else if (!QRegularExpression(
|
||||
"^[a-zA-Z\\- ]+$"
|
||||
"^[a-zA-Z0-9\\.,/&\\-' ]+$"
|
||||
).match(value).hasMatch()) {
|
||||
return lang(lng_passport_bad_name);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ public:
|
||||
AbstractTextRow(
|
||||
QWidget *parent,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value,
|
||||
int limit);
|
||||
|
||||
@@ -101,6 +102,7 @@ public:
|
||||
QWidget *parent,
|
||||
not_null<PanelController*> controller,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value);
|
||||
|
||||
rpl::producer<QString> value() const override;
|
||||
@@ -152,7 +154,11 @@ private:
|
||||
|
||||
class DateRow : public PanelDetailsRow {
|
||||
public:
|
||||
DateRow(QWidget *parent, const QString &label, const QString &value);
|
||||
DateRow(
|
||||
QWidget *parent,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value);
|
||||
|
||||
bool setFocusFast() override;
|
||||
rpl::producer<QString> value() const override;
|
||||
@@ -206,6 +212,7 @@ public:
|
||||
GenderRow(
|
||||
QWidget *parent,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value);
|
||||
|
||||
rpl::producer<QString> value() const override;
|
||||
@@ -247,9 +254,10 @@ template <typename Input>
|
||||
AbstractTextRow<Input>::AbstractTextRow(
|
||||
QWidget *parent,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value,
|
||||
int limit)
|
||||
: PanelDetailsRow(parent, label)
|
||||
: PanelDetailsRow(parent, label, maxLabelWidth)
|
||||
, _field(this, st::passportDetailsField, nullptr, value)
|
||||
, _value(value) {
|
||||
_field->setMaxLength(limit);
|
||||
@@ -299,8 +307,9 @@ CountryRow::CountryRow(
|
||||
QWidget *parent,
|
||||
not_null<PanelController*> controller,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value)
|
||||
: PanelDetailsRow(parent, label)
|
||||
: PanelDetailsRow(parent, label, maxLabelWidth)
|
||||
, _controller(controller)
|
||||
, _link(this, CountryString(value), st::boxLinkButton)
|
||||
, _value(value) {
|
||||
@@ -505,8 +514,9 @@ void DateInput::correctValue(
|
||||
DateRow::DateRow(
|
||||
QWidget *parent,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value)
|
||||
: PanelDetailsRow(parent, label)
|
||||
: PanelDetailsRow(parent, label, maxLabelWidth)
|
||||
, _day(
|
||||
this,
|
||||
st::passportDetailsDateField,
|
||||
@@ -726,25 +736,26 @@ int DateRow::resizeInner(int left, int top, int width) {
|
||||
const auto right = left + width;
|
||||
const auto &_st = st::passportDetailsDateField;
|
||||
const auto &font = _st.placeholderFont;
|
||||
const auto addToWidth = st::passportDetailsSeparatorPadding.left();
|
||||
const auto dayWidth = _st.textMargins.left()
|
||||
+ _st.placeholderMargins.left()
|
||||
+ font->width(lang(lng_date_input_day))
|
||||
+ _st.placeholderMargins.right()
|
||||
+ _st.textMargins.right()
|
||||
+ st::lineWidth;
|
||||
+ addToWidth;
|
||||
const auto monthWidth = _st.textMargins.left()
|
||||
+ _st.placeholderMargins.left()
|
||||
+ font->width(lang(lng_date_input_month))
|
||||
+ _st.placeholderMargins.right()
|
||||
+ _st.textMargins.right()
|
||||
+ st::lineWidth;
|
||||
+ addToWidth;
|
||||
_day->setGeometry(left, top, dayWidth, _day->height());
|
||||
left += dayWidth - st::lineWidth;
|
||||
left += dayWidth - addToWidth;
|
||||
_separator1->resizeToNaturalWidth(width);
|
||||
_separator1->move(left, top);
|
||||
left += _separator1->width();
|
||||
_month->setGeometry(left, top, monthWidth, _month->height());
|
||||
left += monthWidth - st::lineWidth;
|
||||
left += monthWidth - addToWidth;
|
||||
_separator2->resizeToNaturalWidth(width);
|
||||
_separator2->move(left, top);
|
||||
left += _separator2->width();
|
||||
@@ -829,8 +840,9 @@ void DateRow::startBorderAnimation() {
|
||||
GenderRow::GenderRow(
|
||||
QWidget *parent,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value)
|
||||
: PanelDetailsRow(parent, label)
|
||||
: PanelDetailsRow(parent, label, maxLabelWidth)
|
||||
, _group(StringToGender(value).has_value()
|
||||
? std::make_shared<Ui::RadioenumGroup<Gender>>(*StringToGender(value))
|
||||
: std::make_shared<Ui::RadioenumGroup<Gender>>())
|
||||
@@ -938,8 +950,10 @@ void GenderRow::errorAnimationCallback() {
|
||||
|
||||
PanelDetailsRow::PanelDetailsRow(
|
||||
QWidget *parent,
|
||||
const QString &label)
|
||||
: _label(label) {
|
||||
const QString &label,
|
||||
int maxLabelWidth)
|
||||
: _label(label)
|
||||
, _maxLabelWidth(maxLabelWidth) {
|
||||
}
|
||||
|
||||
object_ptr<PanelDetailsRow> PanelDetailsRow::Create(
|
||||
@@ -947,6 +961,7 @@ object_ptr<PanelDetailsRow> PanelDetailsRow::Create(
|
||||
Type type,
|
||||
not_null<PanelController*> controller,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value,
|
||||
const QString &error,
|
||||
int limit) {
|
||||
@@ -956,20 +971,35 @@ object_ptr<PanelDetailsRow> PanelDetailsRow::Create(
|
||||
return object_ptr<AbstractTextRow<Ui::InputField>>(
|
||||
parent,
|
||||
label,
|
||||
maxLabelWidth,
|
||||
value,
|
||||
limit);
|
||||
case Type::Postcode:
|
||||
return object_ptr<AbstractTextRow<PostcodeInput>>(
|
||||
parent,
|
||||
label,
|
||||
maxLabelWidth,
|
||||
value,
|
||||
limit);
|
||||
case Type::Country:
|
||||
return object_ptr<CountryRow>(parent, controller, label, value);
|
||||
return object_ptr<CountryRow>(
|
||||
parent,
|
||||
controller,
|
||||
label,
|
||||
maxLabelWidth,
|
||||
value);
|
||||
case Type::Gender:
|
||||
return object_ptr<GenderRow>(parent, label, value);
|
||||
return object_ptr<GenderRow>(
|
||||
parent,
|
||||
label,
|
||||
maxLabelWidth,
|
||||
value);
|
||||
case Type::Date:
|
||||
return object_ptr<DateRow>(parent, label, value);
|
||||
return object_ptr<DateRow>(
|
||||
parent,
|
||||
label,
|
||||
maxLabelWidth,
|
||||
value);
|
||||
default:
|
||||
Unexpected("Type in PanelDetailsRow::Create.");
|
||||
}
|
||||
@@ -981,13 +1011,19 @@ object_ptr<PanelDetailsRow> PanelDetailsRow::Create(
|
||||
return result;
|
||||
}
|
||||
|
||||
int PanelDetailsRow::LabelWidth(const QString &label) {
|
||||
return st::semiboldFont->width(label);
|
||||
}
|
||||
|
||||
bool PanelDetailsRow::setFocusFast() {
|
||||
return false;
|
||||
}
|
||||
|
||||
int PanelDetailsRow::resizeGetHeight(int newWidth) {
|
||||
const auto padding = st::passportDetailsPadding;
|
||||
const auto inputLeft = padding.left() + st::passportDetailsFieldLeft;
|
||||
const auto inputLeft = padding.left() + std::max(
|
||||
st::passportDetailsFieldLeft,
|
||||
_maxLabelWidth + st::passportDetailsFieldSkipMin);
|
||||
const auto inputTop = st::passportDetailsFieldTop;
|
||||
const auto inputRight = padding.right();
|
||||
const auto inputWidth = std::max(newWidth - inputLeft - inputRight, 0);
|
||||
@@ -997,6 +1033,7 @@ int PanelDetailsRow::resizeGetHeight(int newWidth) {
|
||||
+ (_error ? _error->height() : 0)
|
||||
+ padding.bottom();
|
||||
if (_error) {
|
||||
_error->resizeToWidth(inputWidth);
|
||||
_error->moveToLeft(inputLeft, result - _error->height());
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -37,16 +37,19 @@ public:
|
||||
|
||||
PanelDetailsRow(
|
||||
QWidget *parent,
|
||||
const QString &label);
|
||||
const QString &label,
|
||||
int maxLabelWidth);
|
||||
|
||||
static object_ptr<PanelDetailsRow> Create(
|
||||
QWidget *parent,
|
||||
Type type,
|
||||
not_null<PanelController*> controller,
|
||||
const QString &label,
|
||||
int maxLabelWidth,
|
||||
const QString &value,
|
||||
const QString &error,
|
||||
int limit = 0);
|
||||
static int LabelWidth(const QString &label);
|
||||
|
||||
virtual bool setFocusFast();
|
||||
virtual rpl::producer<QString> value() const = 0;
|
||||
@@ -69,6 +72,7 @@ private:
|
||||
void startErrorAnimation(bool shown);
|
||||
|
||||
QString _label;
|
||||
int _maxLabelWidth = 0;
|
||||
object_ptr<Ui::SlideWrap<Ui::FlatLabel>> _error = { nullptr };
|
||||
bool _errorShown = false;
|
||||
bool _errorHideSubscription = false;
|
||||
|
||||
@@ -326,24 +326,42 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
||||
return ValueField();
|
||||
};
|
||||
|
||||
for (auto i = 0, count = int(_scheme.rows.size()); i != count; ++i) {
|
||||
const auto &row = _scheme.rows[i];
|
||||
auto fields = (row.valueClass == Scheme::ValueClass::Fields)
|
||||
? &data
|
||||
: scanData;
|
||||
if (!fields) {
|
||||
continue;
|
||||
const auto enumerateRows = [&](auto &&callback) {
|
||||
for (auto i = 0, count = int(_scheme.rows.size()); i != count; ++i) {
|
||||
const auto &row = _scheme.rows[i];
|
||||
auto fields = (row.valueClass == Scheme::ValueClass::Fields)
|
||||
? &data
|
||||
: scanData;
|
||||
if (!fields) {
|
||||
continue;
|
||||
}
|
||||
callback(i, row, *fields);
|
||||
}
|
||||
const auto current = valueOrEmpty(*fields, row.key);
|
||||
};
|
||||
auto maxLabelWidth = 0;
|
||||
enumerateRows([&](
|
||||
int i,
|
||||
const EditDocumentScheme::Row &row,
|
||||
const ValueMap &fields) {
|
||||
accumulate_max(
|
||||
maxLabelWidth,
|
||||
PanelDetailsRow::LabelWidth(row.label));
|
||||
});
|
||||
enumerateRows([&](
|
||||
int i,
|
||||
const EditDocumentScheme::Row &row,
|
||||
const ValueMap &fields) {
|
||||
const auto current = valueOrEmpty(fields, row.key);
|
||||
_details.emplace(i, inner->add(PanelDetailsRow::Create(
|
||||
inner,
|
||||
row.inputType,
|
||||
_controller,
|
||||
row.label,
|
||||
maxLabelWidth,
|
||||
current.text,
|
||||
current.error,
|
||||
row.lengthLimit)));
|
||||
}
|
||||
});
|
||||
|
||||
inner->add(
|
||||
object_ptr<Ui::FixedHeightWidget>(inner, st::passportDetailsSkip));
|
||||
|
||||
@@ -326,7 +326,7 @@ void PanelForm::updateControlsGeometry() {
|
||||
_topShadow->moveToLeft(0, 0);
|
||||
_bottomShadow->resizeToWidth(width());
|
||||
_bottomShadow->moveToLeft(0, submitTop - st::lineWidth);
|
||||
_submit->resizeToWidth(width());
|
||||
_submit->setFullWidth(width());
|
||||
_submit->moveToLeft(0, submitTop);
|
||||
|
||||
_scroll->updateBars();
|
||||
|
||||
@@ -199,6 +199,9 @@ bool Get(
|
||||
const QString &filter,
|
||||
Type type,
|
||||
QString startFile) {
|
||||
if (parent) {
|
||||
parent = parent->window();
|
||||
}
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (NativeSupported()) {
|
||||
return GetNative(
|
||||
|
||||
@@ -281,7 +281,9 @@ QString RoundButton::computeFullText() const {
|
||||
|
||||
void RoundButton::resizeToText() {
|
||||
int innerWidth = contentWidth();
|
||||
if (_fullWidthOverride < 0) {
|
||||
if (_fullWidthOverride > 0) {
|
||||
resize(_fullWidthOverride, _st.height + _st.padding.top() + _st.padding.bottom());
|
||||
} else if (_fullWidthOverride < 0) {
|
||||
resize(innerWidth - _fullWidthOverride, _st.height + _st.padding.top() + _st.padding.bottom());
|
||||
} else if (_st.width <= 0) {
|
||||
resize(innerWidth - _st.width + _st.padding.left() + _st.padding.right(), _st.height + _st.padding.top() + _st.padding.bottom());
|
||||
|
||||
@@ -77,7 +77,10 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv
|
||||
CGEventMaskBit(NX_SYSDEFINED),
|
||||
tapEventCallback,
|
||||
self);
|
||||
assert(_eventPort != NULL);
|
||||
if (!_eventPort) {
|
||||
[self stopWatchingMediaKeys];
|
||||
return;
|
||||
}
|
||||
|
||||
_eventPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0);
|
||||
assert(_eventPortSource != NULL);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
AppVersion 1003004
|
||||
AppVersion 1003007
|
||||
AppVersionStrMajor 1.3
|
||||
AppVersionStrSmall 1.3.4
|
||||
AppVersionStr 1.3.4
|
||||
AlphaChannel 1
|
||||
AppVersionStrSmall 1.3.7
|
||||
AppVersionStr 1.3.7
|
||||
AlphaChannel 0
|
||||
BetaVersion 0
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
1.3.7 (11.06.18)
|
||||
|
||||
- Push fixes to stable version.
|
||||
|
||||
1.3.6 alpha (11.06.18)
|
||||
|
||||
- Bug fixes and other minor improvements.
|
||||
|
||||
1.3.5 alpha (08.06.18)
|
||||
|
||||
- Bug fixes and other minor improvements.
|
||||
|
||||
1.3.4 alpha (07.06.18)
|
||||
|
||||
- Bug fixes and other minor improvements.
|
||||
|
||||
Reference in New Issue
Block a user