Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b198c9b975 | ||
|
|
cf7a779689 | ||
|
|
53b3b24867 | ||
|
|
8edf4c8711 | ||
|
|
ad12d6cc46 | ||
|
|
7db7c05da8 | ||
|
|
43d19920e0 | ||
|
|
bfc748cd31 | ||
|
|
b3059248d4 | ||
|
|
0cbad9098e | ||
|
|
5c5438c12e | ||
|
|
734c410879 | ||
|
|
4b4e22d59d | ||
|
|
8f63fa71c9 | ||
|
|
267293d21b | ||
|
|
20ee1fa0d3 | ||
|
|
c70e9b529a | ||
|
|
e42e973ed5 | ||
|
|
03037121aa | ||
|
|
d257b2ee17 | ||
|
|
59a1e13955 | ||
|
|
4e858ba839 | ||
|
|
0eb3d20250 | ||
|
|
c0896f5357 | ||
|
|
f334e2d0f4 | ||
|
|
dfbe11efdb | ||
|
|
becbad32c9 | ||
|
|
46976c4e03 | ||
|
|
1e4cf4c466 | ||
|
|
2e1517474d | ||
|
|
08897aa83a | ||
|
|
7252e9b266 | ||
|
|
07d8dafa5e | ||
|
|
cca46448fe | ||
|
|
3f7947b404 | ||
|
|
4870558827 | ||
|
|
c23ec41622 | ||
|
|
544aef19b4 | ||
|
|
24834ced9e | ||
|
|
10fa6f0c13 | ||
|
|
7a32ad5409 |
@@ -588,7 +588,7 @@ buildCustomQt() {
|
||||
sudo rm -rf "$EXTERNAL/qt${QT_VERSION}"
|
||||
fi
|
||||
cd $QT_PATH
|
||||
rm -rf *
|
||||
sudo rm -rf *
|
||||
|
||||
cd "$EXTERNAL"
|
||||
git clone git://code.qt.io/qt/qt5.git qt${QT_VERSION}
|
||||
|
||||
@@ -172,6 +172,21 @@ inFwdTextPaletteSelected: TextPalette(defaultTextPalette) {
|
||||
outFwdTextPaletteSelected: TextPalette(defaultTextPalette) {
|
||||
linkFg: msgOutServiceFgSelected;
|
||||
}
|
||||
inReplyTextPalette: TextPalette(inTextPalette) {
|
||||
linkFg: msgInDateFg;
|
||||
}
|
||||
inReplyTextPaletteSelected: TextPalette(inTextPaletteSelected) {
|
||||
linkFg: msgInDateFgSelected;
|
||||
}
|
||||
outReplyTextPalette: TextPalette(outTextPalette) {
|
||||
linkFg: msgOutDateFg;
|
||||
}
|
||||
outReplyTextPaletteSelected: TextPalette(outTextPaletteSelected) {
|
||||
linkFg: msgOutDateFgSelected;
|
||||
}
|
||||
imgReplyTextPalette: TextPalette(defaultTextPalette) {
|
||||
linkFg: msgImgReplyBarColor;
|
||||
}
|
||||
inSemiboldPalette: TextPalette(inTextPalette) {
|
||||
linkFg: msgInServiceFg;
|
||||
selectFg: msgInServiceFgSelected;
|
||||
@@ -182,6 +197,9 @@ outSemiboldPalette: TextPalette(outTextPalette) {
|
||||
selectFg: msgOutServiceFgSelected;
|
||||
selectLinkFg: msgOutServiceFgSelected;
|
||||
}
|
||||
historyComposeAreaPalette: TextPalette(defaultTextPalette) {
|
||||
linkFg: historyComposeAreaFgService;
|
||||
}
|
||||
|
||||
mediaCaptionSkip: 5px;
|
||||
mediaInBubbleSkip: 5px;
|
||||
|
||||
@@ -430,10 +430,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_proxy_about" = "Proxy servers may be helpful in accessing Telegram if there is no connection in a specific region.";
|
||||
"lng_proxy_add" = "Add proxy";
|
||||
"lng_proxy_share" = "Share";
|
||||
"lng_proxy_online" = "online";
|
||||
"lng_proxy_online" = "connected";
|
||||
"lng_proxy_checking" = "checking";
|
||||
"lng_proxy_connecting" = "connecting";
|
||||
"lng_proxy_available" = "available (ping: {ping}ms)";
|
||||
"lng_proxy_available" = "available, {ping} ms ping";
|
||||
"lng_proxy_unavailable" = "not available";
|
||||
"lng_proxy_edit" = "Edit proxy";
|
||||
"lng_proxy_menu_edit" = "Edit";
|
||||
@@ -557,6 +557,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_actions_section" = "Actions";
|
||||
"lng_profile_bot_settings" = "Bot Settings";
|
||||
"lng_profile_bot_help" = "Bot Help";
|
||||
"lng_profile_bot_privacy" = "Bot Privacy Policy";
|
||||
"lng_profile_invite_link_section" = "Invite link";
|
||||
"lng_profile_create_public_link" = "Create public link";
|
||||
"lng_profile_edit_public_link" = "Edit public link";
|
||||
@@ -1255,6 +1256,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_new_version_minor" = "— Bug fixes and other minor improvements";
|
||||
|
||||
"lng_menu_insert_unicode" = "Insert Unicode control character";
|
||||
"lng_menu_formatting" = "Formatting";
|
||||
"lng_menu_formatting_bold" = "Bold";
|
||||
"lng_menu_formatting_italic" = "Italic";
|
||||
"lng_menu_formatting_monospace" = "Monospace";
|
||||
"lng_menu_formatting_link_create" = "Create link";
|
||||
"lng_menu_formatting_link_edit" = "Edit link";
|
||||
"lng_menu_formatting_clear" = "Plain text";
|
||||
"lng_formatting_link_create_title" = "Create link";
|
||||
"lng_formatting_link_edit_title" = "Create link";
|
||||
"lng_formatting_link_text" = "Text";
|
||||
"lng_formatting_link_url" = "URL";
|
||||
"lng_formatting_link_create" = "Create";
|
||||
|
||||
"lng_full_name" = "{first_name} {last_name}";
|
||||
|
||||
@@ -1480,6 +1493,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_info_feed_is_default" = "Group new channels";
|
||||
"lng_info_feed_channels" = "Channels";
|
||||
|
||||
"lng_terms_signup" = "By signing up,\nyou agree to the {link}.";
|
||||
"lng_terms_signup_link" = "Terms of Service";
|
||||
"lng_terms_header" = "Terms of Service";
|
||||
"lng_terms_agree" = "Agree & Continue";
|
||||
|
||||
// Wnd specific
|
||||
|
||||
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
387;BA;Bosnia & Herzegovina
|
||||
386;SI;Slovenia
|
||||
385;HR;Croatia
|
||||
383;XK;Kosovo;383 XXXX XXXX;11;
|
||||
382;ME;Montenegro
|
||||
381;RS;Serbia;381 XX XXX XXXX;12;
|
||||
380;UA;Ukraine;380 XX XXX XX XX;12;
|
||||
|
||||
@@ -304,17 +304,10 @@ auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorizat
|
||||
inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
|
||||
inputNotifyUsers#193b4417 = InputNotifyPeer;
|
||||
inputNotifyChats#4a95e84e = InputNotifyPeer;
|
||||
inputNotifyAll#a429b886 = InputNotifyPeer;
|
||||
|
||||
inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents;
|
||||
inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents;
|
||||
inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings;
|
||||
|
||||
inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings;
|
||||
|
||||
peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents;
|
||||
peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents;
|
||||
|
||||
peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings;
|
||||
peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings;
|
||||
|
||||
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
|
||||
|
||||
@@ -515,7 +508,6 @@ help.support#17c6b5f6 phone_number:string user:User = help.Support;
|
||||
notifyPeer#9fd40bd8 peer:Peer = NotifyPeer;
|
||||
notifyUsers#b4c83b4c = NotifyPeer;
|
||||
notifyChats#c007cec3 = NotifyPeer;
|
||||
notifyAll#74d07c60 = NotifyPeer;
|
||||
|
||||
sendMessageTypingAction#16bf744e = SendMessageAction;
|
||||
sendMessageCancelAction#fd5ec8f5 = SendMessageAction;
|
||||
@@ -568,7 +560,7 @@ documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
|
||||
documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
|
||||
|
||||
messages.stickersNotModified#f1749a22 = messages.Stickers;
|
||||
messages.stickers#8a8ecd32 hash:string stickers:Vector<Document> = messages.Stickers;
|
||||
messages.stickers#e4599bbd hash:int stickers:Vector<Document> = messages.Stickers;
|
||||
|
||||
stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
|
||||
|
||||
@@ -697,7 +689,7 @@ messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs;
|
||||
inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
|
||||
@@ -709,7 +701,7 @@ inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:Input
|
||||
botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
|
||||
botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult;
|
||||
@@ -848,6 +840,8 @@ webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vect
|
||||
inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument;
|
||||
|
||||
inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation;
|
||||
inputWebFileGeoPointLocation#66275a62 geo_point:InputGeoPoint w:int h:int zoom:int scale:int = InputWebFileLocation;
|
||||
inputWebFileGeoMessageLocation#553f32eb peer:InputPeer msg_id:int w:int h:int zoom:int scale:int = InputWebFileLocation;
|
||||
|
||||
upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;
|
||||
|
||||
@@ -975,7 +969,6 @@ initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_v
|
||||
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
|
||||
invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
|
||||
|
||||
auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone;
|
||||
auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode;
|
||||
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
|
||||
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
|
||||
@@ -1078,7 +1071,7 @@ messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long da
|
||||
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
|
||||
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
|
||||
messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages;
|
||||
messages.getStickers#85cb5182 flags:# exclude_featured:flags.0?true emoticon:string hash:string = messages.Stickers;
|
||||
messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers;
|
||||
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
|
||||
messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
|
||||
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
|
||||
@@ -1102,8 +1095,8 @@ messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_p
|
||||
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
|
||||
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
|
||||
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
|
||||
messages.editMessage#5d1b8dd flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Updates;
|
||||
messages.editInlineBotMessage#b0e08243 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Bool;
|
||||
messages.editMessage#c000e4c8 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Updates;
|
||||
messages.editInlineBotMessage#adc3e828 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Bool;
|
||||
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
|
||||
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
|
||||
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
|
||||
@@ -1165,7 +1158,7 @@ help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
|
||||
help.getInviteText#4d392343 = help.InviteText;
|
||||
help.getSupport#9cdf08cd = help.Support;
|
||||
help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
|
||||
help.getTermsOfService#350170f3 = help.TermsOfService;
|
||||
help.getTermsOfService#8e59b7e7 country_iso2:string = help.TermsOfService;
|
||||
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
|
||||
help.getCdnConfig#52029342 = CdnConfig;
|
||||
help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
|
||||
@@ -1233,4 +1226,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector<string> = Vector<LangP
|
||||
langpack.getDifference#b2e4d7d from_version:int = LangPackDifference;
|
||||
langpack.getLanguages#800fd57d = Vector<LangPackLanguage>;
|
||||
|
||||
// LAYER 78
|
||||
// LAYER 79
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="1.2.22.0" />
|
||||
Version="1.3.0.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,2,22,0
|
||||
PRODUCTVERSION 1,2,22,0
|
||||
FILEVERSION 1,3,0,0
|
||||
PRODUCTVERSION 1,3,0,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.2.22.0"
|
||||
VALUE "FileVersion", "1.3.0.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.2.22.0"
|
||||
VALUE "ProductVersion", "1.3.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,2,22,0
|
||||
PRODUCTVERSION 1,2,22,0
|
||||
FILEVERSION 1,3,0,0
|
||||
PRODUCTVERSION 1,3,0,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.2.22.0"
|
||||
VALUE "FileVersion", "1.3.0.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.2.22.0"
|
||||
VALUE "ProductVersion", "1.3.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -254,7 +254,7 @@ int main(int argc, const char * argv[]) {
|
||||
forKey:NSWorkspaceLaunchConfigurationArguments]
|
||||
error:&error];
|
||||
if (!result) {
|
||||
writeLog([@"Could not run application, error: " stringByAppendingString:error ? [error localizedDescription] : @"(nil)"]);
|
||||
writeLog([[NSString stringWithFormat:@"Could not run application, error %ld: ", (long)[error code]] stringByAppendingString: error ? [error localizedDescription] : @"(nil)"]);
|
||||
}
|
||||
closeLog();
|
||||
return result ? 0 : -1;
|
||||
|
||||
@@ -62,6 +62,7 @@ constexpr auto kReadFeaturedSetsTimeout = TimeMs(1000);
|
||||
constexpr auto kFileLoaderQueueStopTimeout = TimeMs(5000);
|
||||
constexpr auto kFeedReadTimeout = TimeMs(1000);
|
||||
constexpr auto kStickersByEmojiInvalidateTimeout = TimeMs(60 * 60 * 1000);
|
||||
constexpr auto kNotifySettingSaveTimeout = TimeMs(1000);
|
||||
|
||||
bool IsSilentPost(not_null<HistoryItem*> item, bool silent) {
|
||||
const auto history = item->history();
|
||||
@@ -128,7 +129,7 @@ FileLoadTo FileLoadTaskOptions(const ApiWrap::SendOptions &options) {
|
||||
const auto peer = options.history->peer;
|
||||
return FileLoadTo(
|
||||
peer->id,
|
||||
peer->notifySilentPosts(),
|
||||
Auth().data().notifySilentPosts(peer),
|
||||
options.replyTo);
|
||||
}
|
||||
|
||||
@@ -142,7 +143,8 @@ ApiWrap::ApiWrap(not_null<AuthSession*> session)
|
||||
, _featuredSetsReadTimer([=] { readFeaturedSets(); })
|
||||
, _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout))
|
||||
, _feedReadTimer([=] { readFeeds(); })
|
||||
, _proxyPromotionTimer([=] { refreshProxyPromotion(); }) {
|
||||
, _proxyPromotionTimer([=] { refreshProxyPromotion(); })
|
||||
, _updateNotifySettingsTimer([=] { sendNotifySettingsUpdates(); }) {
|
||||
}
|
||||
|
||||
void ApiWrap::requestChangelog(
|
||||
@@ -273,7 +275,7 @@ void ApiWrap::savePinnedOrder() {
|
||||
// )).done([=](const MTPUpdates &result) {
|
||||
// applyUpdates(result);
|
||||
// if (group) {
|
||||
// channel->setFeed(Auth().data().feed(feedId));
|
||||
// channel->setFeed(_session->data().feed(feedId));
|
||||
// } else {
|
||||
// channel->clearFeed();
|
||||
// }
|
||||
@@ -542,7 +544,7 @@ void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) {
|
||||
|
||||
//case mtpc_dialogFeed: { // #feed
|
||||
// const auto &fields = dialog.c_dialogFeed();
|
||||
// const auto feed = Auth().data().feed(fields.vfeed_id.v);
|
||||
// const auto feed = _session->data().feed(fields.vfeed_id.v);
|
||||
// feed->applyDialog(fields);
|
||||
//} break;
|
||||
}
|
||||
@@ -1376,7 +1378,7 @@ void ApiWrap::deleteAllFromUser(
|
||||
}
|
||||
}
|
||||
|
||||
Auth().data().sendHistoryChangeNotifications();
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
|
||||
deleteAllFromUserSend(channel, from);
|
||||
}
|
||||
@@ -1393,7 +1395,7 @@ void ApiWrap::deleteAllFromUserSend(
|
||||
deleteAllFromUserSend(channel, from);
|
||||
} else if (const auto history = App::historyLoaded(channel)) {
|
||||
if (!history->lastMessageKnown()) {
|
||||
Auth().api().requestDialogEntry(history);
|
||||
requestDialogEntry(history);
|
||||
}
|
||||
}
|
||||
}).send();
|
||||
@@ -1637,83 +1639,137 @@ void ApiWrap::leaveChannel(not_null<ChannelData*> channel) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::blockUser(UserData *user) {
|
||||
void ApiWrap::blockUser(not_null<UserData*> user) {
|
||||
if (user->isBlocked()) {
|
||||
Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserIsBlocked);
|
||||
} else if (!_blockRequests.contains(user)) {
|
||||
} else if (_blockRequests.find(user) == end(_blockRequests)) {
|
||||
auto requestId = request(MTPcontacts_Block(user->inputUser)).done([this, user](const MTPBool &result) {
|
||||
_blockRequests.remove(user);
|
||||
_blockRequests.erase(user);
|
||||
user->setBlockStatus(UserData::BlockStatus::Blocked);
|
||||
}).fail([this, user](const RPCError &error) {
|
||||
_blockRequests.remove(user);
|
||||
_blockRequests.erase(user);
|
||||
}).send();
|
||||
|
||||
_blockRequests.insert(user, requestId);
|
||||
_blockRequests.emplace(user, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::unblockUser(UserData *user) {
|
||||
void ApiWrap::unblockUser(not_null<UserData*> user) {
|
||||
if (!user->isBlocked()) {
|
||||
Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserIsBlocked);
|
||||
} else if (!_blockRequests.contains(user)) {
|
||||
} else if (_blockRequests.find(user) == end(_blockRequests)) {
|
||||
auto requestId = request(MTPcontacts_Unblock(user->inputUser)).done([this, user](const MTPBool &result) {
|
||||
_blockRequests.remove(user);
|
||||
_blockRequests.erase(user);
|
||||
user->setBlockStatus(UserData::BlockStatus::NotBlocked);
|
||||
}).fail([this, user](const RPCError &error) {
|
||||
_blockRequests.remove(user);
|
||||
_blockRequests.erase(user);
|
||||
}).send();
|
||||
|
||||
_blockRequests.insert(user, requestId);
|
||||
_blockRequests.emplace(user, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::exportInviteLink(PeerData *peer) {
|
||||
if (_exportInviteRequests.contains(peer)) {
|
||||
void ApiWrap::exportInviteLink(not_null<PeerData*> peer) {
|
||||
if (_exportInviteRequests.find(peer) != end(_exportInviteRequests)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto sendRequest = [this, peer] {
|
||||
auto exportFail = [this, peer](const RPCError &error) {
|
||||
_exportInviteRequests.remove(peer);
|
||||
const auto sendRequest = [this, peer] {
|
||||
const auto exportFail = [this, peer](const RPCError &error) {
|
||||
_exportInviteRequests.erase(peer);
|
||||
};
|
||||
if (auto chat = peer->asChat()) {
|
||||
return request(MTPmessages_ExportChatInvite(chat->inputChat)).done([this, chat](const MTPExportedChatInvite &result) {
|
||||
_exportInviteRequests.remove(chat);
|
||||
chat->setInviteLink((result.type() == mtpc_chatInviteExported) ? qs(result.c_chatInviteExported().vlink) : QString());
|
||||
if (const auto chat = peer->asChat()) {
|
||||
return request(MTPmessages_ExportChatInvite(
|
||||
chat->inputChat
|
||||
)).done([=](const MTPExportedChatInvite &result) {
|
||||
_exportInviteRequests.erase(chat);
|
||||
chat->setInviteLink(
|
||||
(result.type() == mtpc_chatInviteExported
|
||||
? qs(result.c_chatInviteExported().vlink)
|
||||
: QString()));
|
||||
}).fail(exportFail).send();
|
||||
} else if (auto channel = peer->asChannel()) {
|
||||
return request(MTPchannels_ExportInvite(channel->inputChannel)).done([this, channel](const MTPExportedChatInvite &result) {
|
||||
_exportInviteRequests.remove(channel);
|
||||
channel->setInviteLink((result.type() == mtpc_chatInviteExported) ? qs(result.c_chatInviteExported().vlink) : QString());
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
return request(MTPchannels_ExportInvite(
|
||||
channel->inputChannel
|
||||
)).done([=](const MTPExportedChatInvite &result) {
|
||||
_exportInviteRequests.erase(channel);
|
||||
channel->setInviteLink(
|
||||
(result.type() == mtpc_chatInviteExported
|
||||
? qs(result.c_chatInviteExported().vlink)
|
||||
: QString()));
|
||||
}).fail(exportFail).send();
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
if (auto requestId = sendRequest()) {
|
||||
_exportInviteRequests.insert(peer, requestId);
|
||||
if (const auto requestId = sendRequest()) {
|
||||
_exportInviteRequests.emplace(peer, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::requestNotifySetting(PeerData *peer) {
|
||||
if (_notifySettingRequests.contains(peer)) return;
|
||||
|
||||
auto notifyPeer = MTP_inputNotifyPeer(peer->input);
|
||||
auto requestId = request(MTPaccount_GetNotifySettings(notifyPeer)).done([this, notifyPeer, peer](const MTPPeerNotifySettings &result) {
|
||||
notifySettingReceived(notifyPeer, result);
|
||||
_notifySettingRequests.remove(peer);
|
||||
}).fail([this, notifyPeer, peer](const RPCError &error) {
|
||||
notifySettingReceived(notifyPeer, MTP_peerNotifySettings(
|
||||
MTP_flags(MTPDpeerNotifySettings::Flag::f_show_previews),
|
||||
MTP_int(0),
|
||||
MTP_string("default")));
|
||||
_notifySettingRequests.remove(peer);
|
||||
void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) {
|
||||
const auto key = [&] {
|
||||
switch (peer.type()) {
|
||||
case mtpc_inputNotifyUsers: return peerFromUser(0);
|
||||
case mtpc_inputNotifyChats: return peerFromChat(0);
|
||||
case mtpc_inputNotifyPeer: {
|
||||
const auto &inner = peer.c_inputNotifyPeer().vpeer;
|
||||
switch (inner.type()) {
|
||||
case mtpc_inputPeerSelf:
|
||||
return _session->userPeerId();
|
||||
case mtpc_inputPeerEmpty:
|
||||
return PeerId(0);
|
||||
case mtpc_inputPeerChannel:
|
||||
return peerFromChannel(
|
||||
inner.c_inputPeerChannel().vchannel_id);
|
||||
case mtpc_inputPeerChat:
|
||||
return peerFromChat(inner.c_inputPeerChat().vchat_id);
|
||||
case mtpc_inputPeerUser:
|
||||
return peerFromUser(inner.c_inputPeerUser().vuser_id);
|
||||
}
|
||||
Unexpected("Type in ApiRequest::requestNotifySettings peer.");
|
||||
} break;
|
||||
}
|
||||
Unexpected("Type in ApiRequest::requestNotifySettings.");
|
||||
}();
|
||||
if (_notifySettingRequests.find(key) != end(_notifySettingRequests)) {
|
||||
return;
|
||||
}
|
||||
auto requestId = request(MTPaccount_GetNotifySettings(
|
||||
peer
|
||||
)).done([=](const MTPPeerNotifySettings &result) {
|
||||
notifySettingReceived(peer, result);
|
||||
_notifySettingRequests.erase(key);
|
||||
}).fail([=](const RPCError &error) {
|
||||
notifySettingReceived(peer, MTP_peerNotifySettings(
|
||||
MTP_flags(0),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPint(),
|
||||
MTPstring()));
|
||||
_notifySettingRequests.erase(key);
|
||||
}).send();
|
||||
|
||||
_notifySettingRequests.insert(peer, requestId);
|
||||
_notifySettingRequests.emplace(key, requestId);
|
||||
}
|
||||
|
||||
void ApiWrap::saveDraftToCloudDelayed(History *history) {
|
||||
_draftsSaveRequestIds.insert(history, 0);
|
||||
void ApiWrap::updateNotifySettingsDelayed(not_null<const PeerData*> peer) {
|
||||
_updateNotifySettingsPeers.emplace(peer);
|
||||
_updateNotifySettingsTimer.callOnce(kNotifySettingSaveTimeout);
|
||||
}
|
||||
|
||||
void ApiWrap::sendNotifySettingsUpdates() {
|
||||
while (!_updateNotifySettingsPeers.empty()) {
|
||||
const auto peer = *_updateNotifySettingsPeers.begin();
|
||||
_updateNotifySettingsPeers.erase(_updateNotifySettingsPeers.begin());
|
||||
request(MTPaccount_UpdateNotifySettings(
|
||||
MTP_inputNotifyPeer(peer->input),
|
||||
peer->notifySerialize()
|
||||
)).afterDelay(_updateNotifySettingsPeers.empty() ? 0 : 10).send();
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::saveDraftToCloudDelayed(not_null<History*> history) {
|
||||
_draftsSaveRequestIds.emplace(history, 0);
|
||||
if (!_draftsSaveTimer.isActive()) {
|
||||
_draftsSaveTimer.callOnce(kSaveCloudDraftTimeout);
|
||||
}
|
||||
@@ -1729,6 +1785,7 @@ void ApiWrap::savePrivacy(const MTPInputPrivacyKey &key, QVector<MTPInputPrivacy
|
||||
|
||||
auto requestId = request(MTPaccount_SetPrivacy(key, MTP_vector<MTPInputPrivacyRule>(std::move(rules)))).done([this, keyTypeId](const MTPaccount_PrivacyRules &result) {
|
||||
Expects(result.type() == mtpc_account_privacyRules);
|
||||
|
||||
auto &rules = result.c_account_privacyRules();
|
||||
App::feedUsers(rules.vusers);
|
||||
_privacySaveRequests.remove(keyTypeId);
|
||||
@@ -1904,9 +1961,9 @@ void ApiWrap::applyAffectedMessages(
|
||||
|
||||
void ApiWrap::saveDraftsToCloud() {
|
||||
for (auto i = _draftsSaveRequestIds.begin(), e = _draftsSaveRequestIds.end(); i != e; ++i) {
|
||||
if (i.value()) continue; // sent already
|
||||
if (i->second) continue; // sent already
|
||||
|
||||
auto history = i.key();
|
||||
auto history = i->first;
|
||||
auto cloudDraft = history->cloudDraft();
|
||||
auto localDraft = history->localDraft();
|
||||
if (cloudDraft && cloudDraft->saveRequestId) {
|
||||
@@ -1935,8 +1992,8 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
}
|
||||
}
|
||||
auto i = _draftsSaveRequestIds.find(history);
|
||||
if (i != _draftsSaveRequestIds.cend() && i.value() == requestId) {
|
||||
_draftsSaveRequestIds.remove(history);
|
||||
if (i != _draftsSaveRequestIds.cend() && i->second == requestId) {
|
||||
_draftsSaveRequestIds.erase(history);
|
||||
checkQuitPreventFinished();
|
||||
}
|
||||
}).fail([this, history](const RPCError &error, mtpRequestId requestId) {
|
||||
@@ -1946,18 +2003,18 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
}
|
||||
}
|
||||
auto i = _draftsSaveRequestIds.find(history);
|
||||
if (i != _draftsSaveRequestIds.cend() && i.value() == requestId) {
|
||||
_draftsSaveRequestIds.remove(history);
|
||||
if (i != _draftsSaveRequestIds.cend() && i->second == requestId) {
|
||||
_draftsSaveRequestIds.erase(history);
|
||||
checkQuitPreventFinished();
|
||||
}
|
||||
}).send();
|
||||
|
||||
i.value() = cloudDraft->saveRequestId;
|
||||
i->second = cloudDraft->saveRequestId;
|
||||
}
|
||||
}
|
||||
|
||||
bool ApiWrap::isQuitPrevent() {
|
||||
if (_draftsSaveRequestIds.isEmpty()) {
|
||||
if (_draftsSaveRequestIds.empty()) {
|
||||
return false;
|
||||
}
|
||||
LOG(("ApiWrap prevents quit, saving drafts..."));
|
||||
@@ -1966,7 +2023,7 @@ bool ApiWrap::isQuitPrevent() {
|
||||
}
|
||||
|
||||
void ApiWrap::checkQuitPreventFinished() {
|
||||
if (_draftsSaveRequestIds.isEmpty()) {
|
||||
if (_draftsSaveRequestIds.empty()) {
|
||||
if (App::quitting()) {
|
||||
LOG(("ApiWrap doesn't prevent quit any more."));
|
||||
}
|
||||
@@ -1974,41 +2031,43 @@ void ApiWrap::checkQuitPreventFinished() {
|
||||
}
|
||||
}
|
||||
|
||||
PeerData *ApiWrap::notifySettingReceived(
|
||||
void ApiWrap::notifySettingReceived(
|
||||
MTPInputNotifyPeer notifyPeer,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
PeerData *requestedPeer = nullptr;
|
||||
switch (notifyPeer.type()) {
|
||||
case mtpc_inputNotifyAll:
|
||||
App::main()->applyNotifySetting(MTP_notifyAll(), settings);
|
||||
break;
|
||||
case mtpc_inputNotifyUsers:
|
||||
App::main()->applyNotifySetting(MTP_notifyUsers(), settings);
|
||||
_session->data().applyNotifySetting(MTP_notifyUsers(), settings);
|
||||
break;
|
||||
case mtpc_inputNotifyChats:
|
||||
App::main()->applyNotifySetting(MTP_notifyChats(), settings);
|
||||
_session->data().applyNotifySetting(MTP_notifyChats(), settings);
|
||||
break;
|
||||
case mtpc_inputNotifyPeer: {
|
||||
auto &peer = notifyPeer.c_inputNotifyPeer().vpeer;
|
||||
switch (peer.type()) {
|
||||
case mtpc_inputPeerEmpty: App::main()->applyNotifySetting(
|
||||
MTP_notifyPeer(MTP_peerUser(MTP_int(0))),
|
||||
settings);
|
||||
break;
|
||||
case mtpc_inputPeerSelf: requestedPeer = App::self(); break;
|
||||
case mtpc_inputPeerUser: requestedPeer = App::user(peerFromUser(peer.c_inputPeerUser().vuser_id)); break;
|
||||
case mtpc_inputPeerChat: requestedPeer = App::chat(peerFromChat(peer.c_inputPeerChat().vchat_id)); break;
|
||||
case mtpc_inputPeerChannel: requestedPeer = App::channel(peerFromChannel(peer.c_inputPeerChannel().vchannel_id)); break;
|
||||
}
|
||||
if (requestedPeer) {
|
||||
App::main()->applyNotifySetting(
|
||||
MTP_notifyPeer(peerToMTP(requestedPeer->id)),
|
||||
const auto apply = [&](PeerId peerId) {
|
||||
_session->data().applyNotifySetting(
|
||||
MTP_notifyPeer(peerToMTP(peerId)),
|
||||
settings);
|
||||
};
|
||||
switch (peer.type()) {
|
||||
case mtpc_inputPeerEmpty:
|
||||
apply(0);
|
||||
break;
|
||||
case mtpc_inputPeerSelf:
|
||||
apply(_session->userPeerId());
|
||||
break;
|
||||
case mtpc_inputPeerUser:
|
||||
apply(peerFromUser(peer.c_inputPeerUser().vuser_id));
|
||||
break;
|
||||
case mtpc_inputPeerChat:
|
||||
apply(peerFromChat(peer.c_inputPeerChat().vchat_id));
|
||||
break;
|
||||
case mtpc_inputPeerChannel:
|
||||
apply(peerFromChannel(peer.c_inputPeerChannel().vchannel_id));
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
_session->notifications().checkDelayed();
|
||||
return requestedPeer;
|
||||
}
|
||||
|
||||
void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) {
|
||||
@@ -2325,11 +2384,10 @@ std::vector<not_null<DocumentData*>> *ApiWrap::stickersByEmoji(
|
||||
if (sendRequest) {
|
||||
const auto hash = (it != _stickersByEmoji.end())
|
||||
? it->second.hash
|
||||
: QString();
|
||||
: int32(0);
|
||||
request(MTPmessages_GetStickers(
|
||||
MTP_flags(MTPmessages_GetStickers::Flag::f_exclude_featured),
|
||||
MTP_string(emoji->text()),
|
||||
MTP_string(hash)
|
||||
MTP_int(hash)
|
||||
)).done([=](const MTPmessages_Stickers &result) {
|
||||
if (result.type() == mtpc_messages_stickersNotModified) {
|
||||
return;
|
||||
@@ -2340,12 +2398,12 @@ std::vector<not_null<DocumentData*>> *ApiWrap::stickersByEmoji(
|
||||
entry.list.clear();
|
||||
entry.list.reserve(data.vstickers.v.size());
|
||||
for (const auto &sticker : data.vstickers.v) {
|
||||
const auto document = Auth().data().document(sticker);
|
||||
const auto document = _session->data().document(sticker);
|
||||
if (document->sticker()) {
|
||||
entry.list.push_back(document);
|
||||
}
|
||||
}
|
||||
entry.hash = qs(data.vhash);
|
||||
entry.hash = data.vhash.v;
|
||||
entry.received = getms(true);
|
||||
_session->data().notifyStickersUpdated();
|
||||
}).send();
|
||||
@@ -3490,7 +3548,8 @@ void ApiWrap::forwardMessages(
|
||||
readServerHistory(history);
|
||||
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto silentPost = channelPost && peer->notifySilentPosts();
|
||||
const auto silentPost = channelPost
|
||||
&& _session->data().notifySilentPosts(peer);
|
||||
|
||||
auto flags = MTPDmessage::Flags(0);
|
||||
auto sendFlags = MTPmessages_ForwardMessages::Flags(0);
|
||||
@@ -3665,7 +3724,7 @@ void ApiWrap::sendSharedContact(
|
||||
MTP_string(phone),
|
||||
MTP_string(firstName),
|
||||
MTP_string(lastName));
|
||||
sendMedia(item, media, peer->notifySilentPosts());
|
||||
sendMedia(item, media, _session->data().notifySilentPosts(peer));
|
||||
|
||||
if (const auto main = App::main()) {
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
|
||||
@@ -137,13 +137,13 @@ public:
|
||||
void joinChannel(not_null<ChannelData*> channel);
|
||||
void leaveChannel(not_null<ChannelData*> channel);
|
||||
|
||||
void blockUser(UserData *user);
|
||||
void unblockUser(UserData *user);
|
||||
void blockUser(not_null<UserData*> user);
|
||||
void unblockUser(not_null<UserData*> user);
|
||||
|
||||
void exportInviteLink(PeerData *peer);
|
||||
void requestNotifySetting(PeerData *peer);
|
||||
|
||||
void saveDraftToCloudDelayed(History *history);
|
||||
void exportInviteLink(not_null<PeerData*> peer);
|
||||
void requestNotifySettings(const MTPInputNotifyPeer &peer);
|
||||
void updateNotifySettingsDelayed(not_null<const PeerData*> peer);
|
||||
void saveDraftToCloudDelayed(not_null<History*> history);
|
||||
|
||||
void savePrivacy(const MTPInputPrivacyKey &key, QVector<MTPInputPrivacyRule> &&rules);
|
||||
void handlePrivacyChange(mtpTypeId keyTypeId, const MTPVector<MTPPrivacyRule> &rules);
|
||||
@@ -285,7 +285,7 @@ private:
|
||||
|
||||
struct StickersByEmoji {
|
||||
std::vector<not_null<DocumentData*>> list;
|
||||
QString hash;
|
||||
int32 hash = 0;
|
||||
TimeMs received = 0;
|
||||
};
|
||||
|
||||
@@ -338,7 +338,7 @@ private:
|
||||
MsgRange range,
|
||||
const MTPupdates_ChannelDifference &result);
|
||||
|
||||
PeerData *notifySettingReceived(
|
||||
void notifySettingReceived(
|
||||
MTPInputNotifyPeer peer,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
|
||||
@@ -440,6 +440,8 @@ private:
|
||||
void getProxyPromotionDelayed(TimeId now, TimeId next);
|
||||
void proxyPromotionDone(const MTPhelp_ProxyData &proxy);
|
||||
|
||||
void sendNotifySettingsUpdates();
|
||||
|
||||
not_null<AuthSession*> _session;
|
||||
|
||||
MessageDataRequests _messageDataRequests;
|
||||
@@ -480,12 +482,10 @@ private:
|
||||
QMap<uint64, QPair<uint64, mtpRequestId> > _stickerSetRequests;
|
||||
|
||||
QMap<ChannelData*, mtpRequestId> _channelAmInRequests;
|
||||
QMap<UserData*, mtpRequestId> _blockRequests;
|
||||
QMap<PeerData*, mtpRequestId> _exportInviteRequests;
|
||||
|
||||
QMap<PeerData*, mtpRequestId> _notifySettingRequests;
|
||||
|
||||
QMap<History*, mtpRequestId> _draftsSaveRequestIds;
|
||||
std::map<not_null<UserData*>, mtpRequestId> _blockRequests;
|
||||
std::map<not_null<PeerData*>, mtpRequestId> _exportInviteRequests;
|
||||
std::map<PeerId, mtpRequestId> _notifySettingRequests;
|
||||
std::map<not_null<History*>, mtpRequestId> _draftsSaveRequestIds;
|
||||
base::Timer _draftsSaveTimer;
|
||||
|
||||
base::flat_set<mtpRequestId> _stickerSetDisenableRequests;
|
||||
@@ -575,5 +575,7 @@ private:
|
||||
TimeId _proxyPromotionNextRequestTime = TimeId(0);
|
||||
base::Timer _proxyPromotionTimer;
|
||||
|
||||
base::flat_set<not_null<const PeerData*>> _updateNotifySettingsPeers;
|
||||
base::Timer _updateNotifySettingsTimer;
|
||||
|
||||
};
|
||||
|
||||
@@ -53,9 +53,6 @@ namespace {
|
||||
using PeersData = QHash<PeerId, PeerData*>;
|
||||
PeersData peersData;
|
||||
|
||||
using MutedPeers = QMap<not_null<PeerData*>, bool>;
|
||||
MutedPeers mutedPeers;
|
||||
|
||||
using LocationsData = QHash<LocationCoords, LocationData*>;
|
||||
LocationsData locationsData;
|
||||
|
||||
@@ -1153,14 +1150,23 @@ namespace {
|
||||
return i.value();
|
||||
}
|
||||
|
||||
void enumerateUsers(base::lambda<void(UserData*)> action) {
|
||||
for_const (auto peer, peersData) {
|
||||
if (auto user = peer->asUser()) {
|
||||
void enumerateUsers(base::lambda<void(not_null<UserData*>)> action) {
|
||||
for_const (const auto peer, peersData) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
action(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enumerateChatsChannels(
|
||||
base::lambda<void(not_null<PeerData*>)> action) {
|
||||
for_const (const auto peer, peersData) {
|
||||
if (!peer->isUser()) {
|
||||
action(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UserData *self() {
|
||||
return ::self;
|
||||
}
|
||||
@@ -1309,7 +1315,6 @@ namespace {
|
||||
void historyClearItems() {
|
||||
randomData.clear();
|
||||
sentData.clear();
|
||||
mutedPeers.clear();
|
||||
cSetSavedPeers(SavedPeers());
|
||||
cSetSavedPeersByTime(SavedPeersByTime());
|
||||
cSetRecentInlineBots(RecentInlineBots());
|
||||
@@ -1748,38 +1753,6 @@ namespace {
|
||||
return QPixmap::fromImage(std::move(image), Qt::ColorOnly);
|
||||
}
|
||||
|
||||
void regMuted(not_null<PeerData*> peer, TimeMs changeIn) {
|
||||
::mutedPeers.insert(peer, true);
|
||||
App::main()->updateMutedIn(changeIn);
|
||||
}
|
||||
|
||||
void unregMuted(not_null<PeerData*> peer) {
|
||||
::mutedPeers.remove(peer);
|
||||
}
|
||||
|
||||
void updateMuted() {
|
||||
auto changeInMin = TimeMs(0);
|
||||
for (auto i = ::mutedPeers.begin(); i != ::mutedPeers.end();) {
|
||||
const auto history = App::historyLoaded(i.key()->id);
|
||||
const auto muteFinishesIn = i.key()->notifyMuteFinishesIn();
|
||||
if (muteFinishesIn > 0) {
|
||||
if (history) {
|
||||
history->changeMute(true);
|
||||
}
|
||||
if (!changeInMin || muteFinishesIn < changeInMin) {
|
||||
changeInMin = muteFinishesIn;
|
||||
}
|
||||
++i;
|
||||
} else {
|
||||
if (history) {
|
||||
history->changeMute(false);
|
||||
}
|
||||
i = ::mutedPeers.erase(i);
|
||||
}
|
||||
}
|
||||
if (changeInMin) App::main()->updateMutedIn(changeInMin);
|
||||
}
|
||||
|
||||
void rectWithCorners(Painter &p, QRect rect, const style::color &bg, RoundCorners index, RectParts corners) {
|
||||
auto parts = RectPart::Top
|
||||
| RectPart::NoTopBottom
|
||||
|
||||
@@ -135,7 +135,9 @@ namespace App {
|
||||
inline ChannelData *channelLoaded(ChannelId channelId) {
|
||||
return channel(channelId, PeerData::FullLoaded);
|
||||
}
|
||||
void enumerateUsers(base::lambda<void(UserData*)> action);
|
||||
void enumerateUsers(base::lambda<void(not_null<UserData*>)> action);
|
||||
void enumerateChatsChannels(
|
||||
base::lambda<void(not_null<PeerData*>)> action);
|
||||
|
||||
UserData *self();
|
||||
PeerData *peerByName(const QString &username);
|
||||
@@ -221,10 +223,6 @@ namespace App {
|
||||
QImage readImage(const QString &file, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr, QByteArray *content = 0);
|
||||
QPixmap pixmapFromImageInPlace(QImage &&image);
|
||||
|
||||
void regMuted(not_null<PeerData*> peer, TimeMs changeIn);
|
||||
void unregMuted(not_null<PeerData*> peer);
|
||||
void updateMuted();
|
||||
|
||||
void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, RectParts corners);
|
||||
void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, RectParts corners);
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/crash_reports.h"
|
||||
#include "messenger.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/qthelp_url.h"
|
||||
#include "base/qthelp_regex.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "core/crash_report_window.h"
|
||||
|
||||
|
||||
@@ -122,9 +122,9 @@ void AddContactBox::prepare() {
|
||||
}
|
||||
updateButtons();
|
||||
|
||||
connect(_first, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_last, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_phone, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_first, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); });
|
||||
|
||||
setDimensions(st::boxWideWidth, st::contactPadding.top() + _first->height() + st::contactSkip + _last->height() + st::contactPhoneSkip + _phone->height() + st::contactPadding.bottom() + st::boxPadding.bottom());
|
||||
}
|
||||
@@ -170,21 +170,21 @@ void AddContactBox::resizeEvent(QResizeEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void AddContactBox::onSubmit() {
|
||||
void AddContactBox::submit() {
|
||||
if (_first->hasFocus()) {
|
||||
_last->setFocus();
|
||||
} else if (_last->hasFocus()) {
|
||||
if (_phone->isEnabled()) {
|
||||
_phone->setFocus();
|
||||
} else {
|
||||
onSave();
|
||||
save();
|
||||
}
|
||||
} else if (_phone->hasFocus()) {
|
||||
onSave();
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
void AddContactBox::onSave() {
|
||||
void AddContactBox::save() {
|
||||
if (_addRequest) return;
|
||||
|
||||
auto firstName = TextUtilities::PrepareForSending(_first->getLastText());
|
||||
@@ -274,7 +274,7 @@ void AddContactBox::onSaveUserDone(const MTPcontacts_ImportedContacts &res) {
|
||||
closeBox();
|
||||
}
|
||||
|
||||
void AddContactBox::onRetry() {
|
||||
void AddContactBox::retry() {
|
||||
_addRequest = 0;
|
||||
_contactId = 0;
|
||||
showChildren();
|
||||
@@ -291,9 +291,9 @@ void AddContactBox::onRetry() {
|
||||
void AddContactBox::updateButtons() {
|
||||
clearButtons();
|
||||
if (_retrying) {
|
||||
addButton(langFactory(lng_try_other_contact), [this] { onRetry(); });
|
||||
addButton(langFactory(lng_try_other_contact), [this] { retry(); });
|
||||
} else {
|
||||
addButton(langFactory(_user ? lng_settings_save : lng_add_contact), [this] { onSave(); });
|
||||
addButton(langFactory(_user ? lng_settings_save : lng_add_contact), [this] { save(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
}
|
||||
}
|
||||
@@ -335,14 +335,14 @@ void GroupInfoBox::prepare() {
|
||||
_description->setInstantReplacesEnabled(
|
||||
Global::ReplaceEmojiValue());
|
||||
|
||||
connect(_description, SIGNAL(resized()), this, SLOT(onDescriptionResized()));
|
||||
connect(_description, SIGNAL(submitted(bool)), this, SLOT(onNext()));
|
||||
connect(_description, SIGNAL(cancelled()), this, SLOT(onClose()));
|
||||
connect(_description, &Ui::InputField::resized, [=] { descriptionResized(); });
|
||||
connect(_description, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_description, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
}
|
||||
|
||||
connect(_title, SIGNAL(submitted(bool)), this, SLOT(onNameSubmit()));
|
||||
connect(_title, &Ui::InputField::submitted, [=] { submitName(); });
|
||||
|
||||
addButton(langFactory(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), [this] { onNext(); });
|
||||
addButton(langFactory(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), [this] { submit(); });
|
||||
addButton(langFactory(_fromTypeChoose ? lng_create_group_back : lng_cancel), [this] { closeBox(); });
|
||||
|
||||
updateMaxHeight();
|
||||
@@ -373,14 +373,14 @@ void GroupInfoBox::resizeEvent(QResizeEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void GroupInfoBox::onNameSubmit() {
|
||||
void GroupInfoBox::submitName() {
|
||||
if (_title->getLastText().trimmed().isEmpty()) {
|
||||
_title->setFocus();
|
||||
_title->showError();
|
||||
} else if (_description) {
|
||||
_description->setFocus();
|
||||
} else {
|
||||
onNext();
|
||||
submit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,11 +460,15 @@ void GroupInfoBox::createGroup(not_null<PeerListBox*> selectUsersBox, const QStr
|
||||
}).send();
|
||||
}
|
||||
|
||||
void GroupInfoBox::onNext() {
|
||||
void GroupInfoBox::submit() {
|
||||
if (_creationRequestId) return;
|
||||
|
||||
auto title = TextUtilities::PrepareForSending(_title->getLastText());
|
||||
auto description = _description ? TextUtilities::PrepareForSending(_description->getLastText(), TextUtilities::PrepareTextOption::CheckLinks) : QString();
|
||||
auto description = _description
|
||||
? TextUtilities::PrepareForSending(
|
||||
_description->getLastText(),
|
||||
TextUtilities::PrepareTextOption::CheckLinks)
|
||||
: QString();
|
||||
if (title.isEmpty()) {
|
||||
_title->setFocus();
|
||||
_title->showError();
|
||||
@@ -560,7 +564,7 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
|
||||
}).send();
|
||||
}
|
||||
|
||||
void GroupInfoBox::onDescriptionResized() {
|
||||
void GroupInfoBox::descriptionResized() {
|
||||
updateMaxHeight();
|
||||
update();
|
||||
}
|
||||
@@ -598,14 +602,14 @@ void SetupChannelBox::prepare() {
|
||||
|
||||
_checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail));
|
||||
|
||||
addButton(langFactory(lng_settings_save), [this] { onSave(); });
|
||||
addButton(langFactory(_existing ? lng_cancel : lng_create_group_skip), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_settings_save), [=] { save(); });
|
||||
addButton(langFactory(_existing ? lng_cancel : lng_create_group_skip), [=] { closeBox(); });
|
||||
|
||||
connect(_link, SIGNAL(changed()), this, SLOT(onChange()));
|
||||
connect(_link, &Ui::MaskedInputField::changed, [=] { handleChange(); });
|
||||
_link->setVisible(_privacyGroup->value() == Privacy::Public);
|
||||
|
||||
_checkTimer.setSingleShot(true);
|
||||
connect(&_checkTimer, SIGNAL(timeout()), this, SLOT(onCheck()));
|
||||
connect(&_checkTimer, &QTimer::timeout, [=] { check(); });
|
||||
|
||||
_privacyGroup->setChangedCallback([this](Privacy value) { privacyChanged(value); });
|
||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::InviteLinkChanged, [this](const Notify::PeerUpdate &update) {
|
||||
@@ -644,7 +648,7 @@ void SetupChannelBox::keyPressEvent(QKeyEvent *e) {
|
||||
_link->setFocus();
|
||||
_link->showError();
|
||||
} else {
|
||||
onSave();
|
||||
save();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -733,7 +737,7 @@ void SetupChannelBox::updateSelected(const QPoint &cursorGlobalPosition) {
|
||||
}
|
||||
}
|
||||
|
||||
void SetupChannelBox::onSave() {
|
||||
void SetupChannelBox::save() {
|
||||
if (_privacyGroup->value() == Privacy::Private) {
|
||||
if (_existing) {
|
||||
_sentUsername = QString();
|
||||
@@ -756,7 +760,7 @@ void SetupChannelBox::onSave() {
|
||||
_saveRequestId = MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail));
|
||||
}
|
||||
|
||||
void SetupChannelBox::onChange() {
|
||||
void SetupChannelBox::handleChange() {
|
||||
QString name = _link->text().trimmed();
|
||||
if (name.isEmpty()) {
|
||||
if (!_errorText.isEmpty() || !_goodText.isEmpty()) {
|
||||
@@ -793,7 +797,7 @@ void SetupChannelBox::onChange() {
|
||||
}
|
||||
}
|
||||
|
||||
void SetupChannelBox::onCheck() {
|
||||
void SetupChannelBox::check() {
|
||||
if (_checkRequestId) {
|
||||
MTP::cancel(_checkRequestId);
|
||||
}
|
||||
@@ -816,7 +820,7 @@ void SetupChannelBox::privacyChanged(Privacy value) {
|
||||
Ui::show(Box<RevokePublicLinkBox>(base::lambda_guarded(this, [this] {
|
||||
_tooMuchUsernames = false;
|
||||
_privacyGroup->setValue(Privacy::Public);
|
||||
onCheck();
|
||||
check();
|
||||
})), LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
@@ -952,16 +956,16 @@ void EditNameBox::prepare() {
|
||||
newHeight += st::boxPadding.bottom() + st::contactPadding.bottom();
|
||||
setDimensions(st::boxWideWidth, newHeight);
|
||||
|
||||
addButton(langFactory(lng_settings_save), [this] { save(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_settings_save), [=] { save(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
if (_invertOrder) {
|
||||
setTabOrder(_last, _first);
|
||||
}
|
||||
_first->setMaxLength(kMaxGroupChannelTitle);
|
||||
_last->setMaxLength(kMaxGroupChannelTitle);
|
||||
|
||||
connect(_first, &Ui::InputField::submitted, this, [this] { submit(); });
|
||||
connect(_last, &Ui::InputField::submitted, this, [this] { submit(); });
|
||||
connect(_first, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
|
||||
}
|
||||
|
||||
void EditNameBox::setInnerFocus() {
|
||||
@@ -1081,9 +1085,9 @@ void EditBioBox::prepare() {
|
||||
auto cursor = _bio->textCursor();
|
||||
cursor.setPosition(_bio->getLastText().size());
|
||||
_bio->setTextCursor(cursor);
|
||||
connect(_bio, &Ui::InputField::submitted, this, [this](bool ctrlShiftEnter) { save(); });
|
||||
connect(_bio, &Ui::InputField::resized, this, [this] { updateMaxHeight(); });
|
||||
connect(_bio, &Ui::InputField::changed, this, [this] { handleBioUpdated(); });
|
||||
connect(_bio, &Ui::InputField::submitted, [=] { save(); });
|
||||
connect(_bio, &Ui::InputField::resized, [=] { updateMaxHeight(); });
|
||||
connect(_bio, &Ui::InputField::changed, [=] { handleBioUpdated(); });
|
||||
_bio->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
_bio->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
handleBioUpdated();
|
||||
@@ -1154,7 +1158,7 @@ EditChannelBox::EditChannelBox(QWidget*, not_null<ChannelData*> channel)
|
||||
void EditChannelBox::prepare() {
|
||||
setTitle(langFactory(_channel->isMegagroup() ? lng_edit_group : lng_edit_channel_title));
|
||||
|
||||
addButton(langFactory(lng_settings_save), [this] { onSave(); });
|
||||
addButton(langFactory(lng_settings_save), [this] { save(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
|
||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::NameChanged, [this](const Notify::PeerUpdate &update) {
|
||||
@@ -1172,11 +1176,11 @@ void EditChannelBox::prepare() {
|
||||
_description->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
_description->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
|
||||
connect(_description, SIGNAL(resized()), this, SLOT(onDescriptionResized()));
|
||||
connect(_description, SIGNAL(submitted(bool)), this, SLOT(onSave()));
|
||||
connect(_description, SIGNAL(cancelled()), this, SLOT(onClose()));
|
||||
connect(_description, &Ui::InputField::resized, [=] { descriptionResized(); });
|
||||
connect(_description, &Ui::InputField::submitted, [=] { save(); });
|
||||
connect(_description, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
|
||||
connect(_publicLink, SIGNAL(clicked()), this, SLOT(onPublicLink()));
|
||||
_publicLink->addClickHandler([=] { setupPublicLink(); });
|
||||
_publicLink->setVisible(_channel->canEditUsername());
|
||||
_sign->setVisible(canEditSignatures());
|
||||
_inviteEverybody->setVisible(canEditInvites());
|
||||
@@ -1192,7 +1196,7 @@ void EditChannelBox::setInnerFocus() {
|
||||
void EditChannelBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
if (_title->hasFocus()) {
|
||||
onSave();
|
||||
save();
|
||||
}
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
@@ -1204,7 +1208,7 @@ void EditChannelBox::handleChannelNameChange() {
|
||||
_sign->setChecked(_channel->addsSignature());
|
||||
}
|
||||
|
||||
void EditChannelBox::onDescriptionResized() {
|
||||
void EditChannelBox::descriptionResized() {
|
||||
updateMaxHeight();
|
||||
update();
|
||||
}
|
||||
@@ -1268,7 +1272,7 @@ void EditChannelBox::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void EditChannelBox::onSave() {
|
||||
void EditChannelBox::save() {
|
||||
if (_saveTitleRequestId || _saveDescriptionRequestId || _saveSignRequestId || _saveInvitesRequestId) return;
|
||||
|
||||
auto title = TextUtilities::PrepareForSending(_title->getLastText());
|
||||
@@ -1287,7 +1291,7 @@ void EditChannelBox::onSave() {
|
||||
}
|
||||
}
|
||||
|
||||
void EditChannelBox::onPublicLink() {
|
||||
void EditChannelBox::setupPublicLink() {
|
||||
Ui::show(
|
||||
Box<SetupChannelBox>(_channel, true),
|
||||
LayerOption::KeepOther);
|
||||
|
||||
@@ -36,8 +36,6 @@ enum class PeerFloodType {
|
||||
QString PeerFloodErrorText(PeerFloodType type);
|
||||
|
||||
class AddContactBox : public BoxContent, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AddContactBox(QWidget*, QString fname = QString(), QString lname = QString(), QString phone = QString());
|
||||
AddContactBox(QWidget*, UserData *user);
|
||||
@@ -50,12 +48,10 @@ protected:
|
||||
|
||||
void setInnerFocus() override;
|
||||
|
||||
private slots:
|
||||
void onSubmit();
|
||||
void onSave();
|
||||
void onRetry();
|
||||
|
||||
private:
|
||||
void submit();
|
||||
void retry();
|
||||
void save();
|
||||
void updateButtons();
|
||||
void onImportDone(const MTPcontacts_ImportedContacts &res);
|
||||
|
||||
@@ -79,8 +75,6 @@ private:
|
||||
};
|
||||
|
||||
class GroupInfoBox : public BoxContent, private MTP::Sender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GroupInfoBox(QWidget*, CreatingGroupType creating, bool fromTypeChoose);
|
||||
|
||||
@@ -90,18 +84,13 @@ protected:
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private slots:
|
||||
void onNext();
|
||||
void onNameSubmit();
|
||||
void onDescriptionResized();
|
||||
void onClose() {
|
||||
closeBox();
|
||||
}
|
||||
|
||||
private:
|
||||
void createChannel(const QString &title, const QString &description);
|
||||
void createGroup(not_null<PeerListBox*> selectUsersBox, const QString &title, const std::vector<not_null<PeerData*>> &users);
|
||||
void submitName();
|
||||
void submit();
|
||||
|
||||
void descriptionResized();
|
||||
void updateMaxHeight();
|
||||
void updateSelected(const QPoint &cursorGlobalPosition);
|
||||
|
||||
@@ -119,8 +108,6 @@ private:
|
||||
};
|
||||
|
||||
class SetupChannelBox : public BoxContent, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SetupChannelBox(QWidget*, ChannelData *channel, bool existing = false);
|
||||
|
||||
@@ -136,11 +123,6 @@ protected:
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
|
||||
private slots:
|
||||
void onSave();
|
||||
void onChange();
|
||||
void onCheck();
|
||||
|
||||
private:
|
||||
enum class Privacy {
|
||||
Public,
|
||||
@@ -149,6 +131,9 @@ private:
|
||||
void privacyChanged(Privacy value);
|
||||
void updateSelected(const QPoint &cursorGlobalPosition);
|
||||
void showAddContactsToChannelBox() const;
|
||||
void handleChange();
|
||||
void check();
|
||||
void save();
|
||||
|
||||
void onUpdateDone(const MTPBool &result);
|
||||
bool onUpdateFail(const RPCError &error);
|
||||
@@ -239,8 +224,6 @@ private:
|
||||
};
|
||||
|
||||
class EditChannelBox : public BoxContent, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditChannelBox(QWidget*, not_null<ChannelData*> channel);
|
||||
|
||||
@@ -252,19 +235,14 @@ protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private slots:
|
||||
void onSave();
|
||||
void onDescriptionResized();
|
||||
void onPublicLink();
|
||||
void onClose() {
|
||||
closeBox();
|
||||
}
|
||||
|
||||
private:
|
||||
void updateMaxHeight();
|
||||
bool canEditSignatures() const;
|
||||
bool canEditInvites() const;
|
||||
void handleChannelNameChange();
|
||||
void descriptionResized();
|
||||
void setupPublicLink();
|
||||
void save();
|
||||
|
||||
void onSaveTitleDone(const MTPUpdates &result);
|
||||
void onSaveDescriptionDone(const MTPBool &result);
|
||||
|
||||
@@ -782,3 +782,5 @@ proxyDropdownUpPosition: point(-2px, 20px);
|
||||
|
||||
proxyAboutPadding: margins(22px, 7px, 22px, 14px);
|
||||
proxyAboutSponsorPadding: margins(22px, 7px, 22px, 0px);
|
||||
|
||||
markdownLinkFieldPadding: margins(22px, 0px, 22px, 10px);
|
||||
|
||||
@@ -125,7 +125,7 @@ void ChangePhoneBox::EnterPhone::prepare() {
|
||||
|
||||
_phone->resize(st::boxWidth - 2 * st::boxPadding.left(), _phone->height());
|
||||
_phone->moveToLeft(st::boxPadding.left(), st::boxLittleSkip);
|
||||
connect(_phone, &Ui::PhoneInput::submitted, this, [this] { submit(); });
|
||||
connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); });
|
||||
|
||||
auto description = object_ptr<Ui::FlatLabel>(this, lang(lng_change_phone_new_description), Ui::FlatLabel::InitType::Simple, st::changePhoneLabel);
|
||||
auto errorSkip = st::boxLittleSkip + st::changePhoneError.style.font->height;
|
||||
@@ -225,12 +225,12 @@ void ChangePhoneBox::EnterCode::prepare() {
|
||||
|
||||
auto phoneValue = QString();
|
||||
_code.create(this, st::defaultInputField, langFactory(lng_change_phone_code_title), phoneValue);
|
||||
_code->setAutoSubmit(_codeLength, [this] { submit(); });
|
||||
_code->setChangedCallback([this] { hideError(); });
|
||||
_code->setAutoSubmit(_codeLength, [=] { submit(); });
|
||||
_code->setChangedCallback([=] { hideError(); });
|
||||
|
||||
_code->resize(st::boxWidth - 2 * st::boxPadding.left(), _code->height());
|
||||
_code->moveToLeft(st::boxPadding.left(), description->bottomNoMargins());
|
||||
connect(_code, &Ui::InputField::submitted, this, [this] { submit(); });
|
||||
connect(_code, &Ui::InputField::submitted, [=] { submit(); });
|
||||
|
||||
setDimensions(st::boxWidth, countHeight());
|
||||
|
||||
@@ -239,8 +239,8 @@ void ChangePhoneBox::EnterCode::prepare() {
|
||||
updateCall();
|
||||
}
|
||||
|
||||
addButton(langFactory(lng_change_phone_new_submit), [this] { submit(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_change_phone_new_submit), [=] { submit(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
}
|
||||
|
||||
int ChangePhoneBox::EnterCode::countHeight() {
|
||||
|
||||
@@ -119,9 +119,19 @@ void ConfirmBox::prepare() {
|
||||
textUpdated();
|
||||
}
|
||||
|
||||
void ConfirmBox::setMaxLineCount(int count) {
|
||||
if (_maxLineCount != count) {
|
||||
_maxLineCount = count;
|
||||
textUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmBox::textUpdated() {
|
||||
_textWidth = st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right();
|
||||
_textHeight = qMin(_text.countHeight(_textWidth), 16 * st::boxLabelStyle.lineHeight);
|
||||
_textHeight = _text.countHeight(_textWidth);
|
||||
if (_maxLineCount > 0) {
|
||||
accumulate_min(_textHeight, _maxLineCount * st::boxLabelStyle.lineHeight);
|
||||
}
|
||||
setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
|
||||
|
||||
setMouseTracking(_text.hasLinks());
|
||||
@@ -198,7 +208,11 @@ void ConfirmBox::paintEvent(QPaintEvent *e) {
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::boxTextFg);
|
||||
_text.drawLeftElided(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), 16, style::al_left);
|
||||
if (_maxLineCount > 0) {
|
||||
_text.drawLeftElided(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), _maxLineCount, style::al_left);
|
||||
} else {
|
||||
_text.drawLeft(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), style::al_left);
|
||||
}
|
||||
}
|
||||
|
||||
InformBox::InformBox(QWidget*, const QString &text, base::lambda<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, lang(lng_box_ok), std::move(closedCallback)) {
|
||||
|
||||
@@ -31,6 +31,8 @@ public:
|
||||
_strictCancel = strictCancel;
|
||||
}
|
||||
|
||||
void setMaxLineCount(int count);
|
||||
|
||||
// ClickHandlerHost interface
|
||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||
@@ -55,6 +57,7 @@ private:
|
||||
void confirmed();
|
||||
void init(const QString &text);
|
||||
void textUpdated();
|
||||
void updateHover();
|
||||
|
||||
QString _confirmText;
|
||||
QString _cancelText;
|
||||
@@ -64,8 +67,7 @@ private:
|
||||
Text _text;
|
||||
int _textWidth = 0;
|
||||
int _textHeight = 0;
|
||||
|
||||
void updateHover();
|
||||
int _maxLineCount = 16;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
|
||||
@@ -198,17 +198,17 @@ void ConfirmPhoneBox::prepare() {
|
||||
_about->setMarkedText(aboutText);
|
||||
|
||||
_code.create(this, st::confirmPhoneCodeField, langFactory(lng_code_ph));
|
||||
_code->setAutoSubmit(_sentCodeLength, [this] { onSendCode(); });
|
||||
_code->setChangedCallback([this] { showError(QString()); });
|
||||
_code->setAutoSubmit(_sentCodeLength, [=] { sendCode(); });
|
||||
_code->setChangedCallback([=] { showError(QString()); });
|
||||
|
||||
setTitle(langFactory(lng_confirm_phone_title));
|
||||
|
||||
addButton(langFactory(lng_confirm_phone_send), [this] { onSendCode(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_confirm_phone_send), [=] { sendCode(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWidth, st::usernamePadding.top() + _code->height() + st::usernameSkip + _about->height() + st::usernameSkip);
|
||||
|
||||
connect(_code, SIGNAL(submitted(bool)), this, SLOT(onSendCode()));
|
||||
connect(_code, &Ui::InputField::submitted, [=] { sendCode(); });
|
||||
|
||||
showChildren();
|
||||
}
|
||||
@@ -217,7 +217,7 @@ void ConfirmPhoneBox::callDone(const MTPauth_SentCode &result) {
|
||||
_call.callDone();
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::onSendCode() {
|
||||
void ConfirmPhoneBox::sendCode() {
|
||||
if (_sendCodeRequestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,16 +82,11 @@ private:
|
||||
};
|
||||
|
||||
class ConfirmPhoneBox : public BoxContent, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static void start(const QString &phone, const QString &hash);
|
||||
|
||||
~ConfirmPhoneBox();
|
||||
|
||||
private slots:
|
||||
void onSendCode();
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
void setInnerFocus() override;
|
||||
@@ -103,6 +98,7 @@ private:
|
||||
ConfirmPhoneBox(QWidget*, const QString &phone, const QString &hash);
|
||||
friend class object_ptr<ConfirmPhoneBox>;
|
||||
|
||||
void sendCode();
|
||||
void sendCall();
|
||||
void checkPhoneAndHash();
|
||||
|
||||
|
||||
@@ -25,8 +25,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
EditCaptionBox::EditCaptionBox(
|
||||
QWidget*,
|
||||
not_null<Window::Controller*> controller,
|
||||
not_null<HistoryItem*> item)
|
||||
: _msgId(item->fullId()) {
|
||||
: _controller(controller)
|
||||
, _msgId(item->fullId()) {
|
||||
Expects(item->media() != nullptr);
|
||||
Expects(item->media()->allowsEditCaption());
|
||||
|
||||
@@ -145,7 +147,9 @@ EditCaptionBox::EditCaptionBox(
|
||||
_field->setSubmitSettings(Ui::InputField::SubmitSettings::Both);
|
||||
_field->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
_field->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
_field->setMarkdownReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
_field->setMarkdownReplacesEnabled(rpl::single(true));
|
||||
_field->setEditLinkCallback(
|
||||
DefaultEditLinkCallback(_controller, _field));
|
||||
}
|
||||
|
||||
void EditCaptionBox::prepareGifPreview(DocumentData *document) {
|
||||
@@ -190,13 +194,9 @@ void EditCaptionBox::prepare() {
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
|
||||
updateBoxSize();
|
||||
connect(_field, &Ui::InputField::submitted, this, [this] { save(); });
|
||||
connect(_field, &Ui::InputField::cancelled, this, [this] {
|
||||
closeBox();
|
||||
});
|
||||
connect(_field, &Ui::InputField::resized, this, [this] {
|
||||
captionResized();
|
||||
});
|
||||
connect(_field, &Ui::InputField::submitted, [=] { save(); });
|
||||
connect(_field, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
connect(_field, &Ui::InputField::resized, [=] { captionResized(); });
|
||||
|
||||
auto cursor = _field->textCursor();
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
@@ -345,7 +345,7 @@ void EditCaptionBox::save() {
|
||||
if (_previewCancelled) {
|
||||
flags |= MTPmessages_EditMessage::Flag::f_no_webpage;
|
||||
}
|
||||
const auto textWithTags = _field->getTextWithTags();
|
||||
const auto textWithTags = _field->getTextWithAppliedMarkdown();
|
||||
auto sending = TextWithEntities{
|
||||
textWithTags.text,
|
||||
ConvertTextTagsToEntities(textWithTags.tags)
|
||||
@@ -368,6 +368,7 @@ void EditCaptionBox::save() {
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id),
|
||||
MTP_string(sending.text),
|
||||
MTPInputMedia(),
|
||||
MTPnullMarkup,
|
||||
sentEntities,
|
||||
MTP_inputGeoPointEmpty()),
|
||||
|
||||
@@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
|
||||
namespace Window {
|
||||
class Controller;
|
||||
} // namespace Window
|
||||
|
||||
namespace Data {
|
||||
class Media;
|
||||
} // namespace Data
|
||||
@@ -19,7 +23,10 @@ class InputField;
|
||||
|
||||
class EditCaptionBox : public BoxContent, public RPCSender {
|
||||
public:
|
||||
EditCaptionBox(QWidget*, not_null<HistoryItem*> item);
|
||||
EditCaptionBox(
|
||||
QWidget*,
|
||||
not_null<Window::Controller*> controller,
|
||||
not_null<HistoryItem*> item);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@@ -41,6 +48,7 @@ private:
|
||||
|
||||
int errorTopSkip() const;
|
||||
|
||||
not_null<Window::Controller*> _controller;
|
||||
FullMsgId _msgId;
|
||||
bool _animated = false;
|
||||
bool _photo = false;
|
||||
|
||||
@@ -630,34 +630,36 @@ EditColorBox::EditColorBox(QWidget*, const QString &title, QColor current) : Box
|
||||
}
|
||||
|
||||
void EditColorBox::prepare() {
|
||||
setTitle([this] { return _title; });
|
||||
setTitle([=] { return _title; });
|
||||
|
||||
connect(_hueField, SIGNAL(changed()), this, SLOT(onFieldChanged()));
|
||||
connect(_saturationField, SIGNAL(changed()), this, SLOT(onFieldChanged()));
|
||||
connect(_brightnessField, SIGNAL(changed()), this, SLOT(onFieldChanged()));
|
||||
connect(_redField, SIGNAL(changed()), this, SLOT(onFieldChanged()));
|
||||
connect(_greenField, SIGNAL(changed()), this, SLOT(onFieldChanged()));
|
||||
connect(_blueField, SIGNAL(changed()), this, SLOT(onFieldChanged()));
|
||||
connect(_result, SIGNAL(changed()), this, SLOT(onFieldChanged()));
|
||||
const auto changed = [=] { fieldChanged(); };
|
||||
connect(_hueField, &Ui::MaskedInputField::changed, changed);
|
||||
connect(_saturationField, &Ui::MaskedInputField::changed, changed);
|
||||
connect(_brightnessField, &Ui::MaskedInputField::changed, changed);
|
||||
connect(_redField, &Ui::MaskedInputField::changed, changed);
|
||||
connect(_greenField, &Ui::MaskedInputField::changed, changed);
|
||||
connect(_blueField, &Ui::MaskedInputField::changed, changed);
|
||||
connect(_result, &Ui::MaskedInputField::changed, changed);
|
||||
|
||||
connect(_hueField, SIGNAL(submitted(bool)), this, SLOT(onFieldSubmitted()));
|
||||
connect(_saturationField, SIGNAL(submitted(bool)), this, SLOT(onFieldSubmitted()));
|
||||
connect(_brightnessField, SIGNAL(submitted(bool)), this, SLOT(onFieldSubmitted()));
|
||||
connect(_redField, SIGNAL(submitted(bool)), this, SLOT(onFieldSubmitted()));
|
||||
connect(_greenField, SIGNAL(submitted(bool)), this, SLOT(onFieldSubmitted()));
|
||||
connect(_blueField, SIGNAL(submitted(bool)), this, SLOT(onFieldSubmitted()));
|
||||
connect(_result, SIGNAL(submitted(bool)), this, SLOT(onFieldSubmitted()));
|
||||
const auto submitted = [=] { fieldSubmitted(); };
|
||||
connect(_hueField, &Ui::MaskedInputField::submitted, submitted);
|
||||
connect(_saturationField, &Ui::MaskedInputField::submitted, submitted);
|
||||
connect(_brightnessField, &Ui::MaskedInputField::submitted, submitted);
|
||||
connect(_redField, &Ui::MaskedInputField::submitted, submitted);
|
||||
connect(_greenField, &Ui::MaskedInputField::submitted, submitted);
|
||||
connect(_blueField, &Ui::MaskedInputField::submitted, submitted);
|
||||
connect(_result, &Ui::MaskedInputField::submitted, submitted);
|
||||
|
||||
addButton(langFactory(lng_settings_save), [this] { saveColor(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_settings_save), [=] { saveColor(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
auto height = st::colorEditSkip + st::colorPickerSize + st::colorEditSkip + st::colorSliderWidth + st::colorEditSkip;
|
||||
setDimensions(st::colorEditWidth, height);
|
||||
|
||||
subscribe(_picker->changed(), [this] { updateFromControls(); });
|
||||
subscribe(_hueSlider->changed(), [this] { updateFromControls(); });
|
||||
subscribe(_opacitySlider->changed(), [this] { updateFromControls(); });
|
||||
subscribe(boxClosing, [this] {
|
||||
subscribe(_picker->changed(), [=] { updateFromControls(); });
|
||||
subscribe(_hueSlider->changed(), [=] { updateFromControls(); });
|
||||
subscribe(_opacitySlider->changed(), [=] { updateFromControls(); });
|
||||
subscribe(boxClosing, [=] {
|
||||
if (_cancelCallback) {
|
||||
_cancelCallback();
|
||||
}
|
||||
@@ -670,7 +672,7 @@ void EditColorBox::setInnerFocus() {
|
||||
_result->selectAll();
|
||||
}
|
||||
|
||||
void EditColorBox::onFieldChanged() {
|
||||
void EditColorBox::fieldChanged() {
|
||||
auto emitter = sender();
|
||||
auto checkHSVSender = [this, emitter](QObject *field) {
|
||||
if (emitter == field) {
|
||||
@@ -693,7 +695,7 @@ void EditColorBox::onFieldChanged() {
|
||||
}
|
||||
}
|
||||
|
||||
void EditColorBox::onFieldSubmitted() {
|
||||
void EditColorBox::fieldSubmitted() {
|
||||
Ui::MaskedInputField *fields[] = {
|
||||
_hueField,
|
||||
_saturationField,
|
||||
|
||||
@@ -10,8 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/abstract_box.h"
|
||||
|
||||
class EditColorBox : public BoxContent {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditColorBox(QWidget*, const QString &title, QColor current = QColor(255, 255, 255));
|
||||
|
||||
@@ -37,12 +35,10 @@ protected:
|
||||
|
||||
void setInnerFocus() override;
|
||||
|
||||
private slots:
|
||||
void onFieldChanged();
|
||||
void onFieldSubmitted();
|
||||
|
||||
private:
|
||||
void saveColor();
|
||||
void fieldChanged();
|
||||
void fieldSubmitted();
|
||||
|
||||
void updateFromColor(QColor color);
|
||||
void updateControlsFromColor();
|
||||
|
||||
@@ -8,7 +8,8 @@ Copyright (C) 2017, Nicholas Guriev <guriev-ns@ya.ru>
|
||||
#include "boxes/mute_settings_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "auth_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
@@ -69,10 +70,8 @@ void MuteSettingsBox::prepare() {
|
||||
|
||||
addButton(langFactory(lng_box_ok), [this, group] {
|
||||
auto muteForSeconds = group->value() * 3600;
|
||||
App::main()->updateNotifySettings(
|
||||
Auth().data().updateNotifySettings(
|
||||
_peer,
|
||||
Data::NotifySettings::MuteChange::Mute,
|
||||
Data::NotifySettings::SilentPostsChange::Ignore,
|
||||
muteForSeconds);
|
||||
closeBox();
|
||||
});
|
||||
|
||||
@@ -43,8 +43,8 @@ PasscodeBox::PasscodeBox(QWidget*, const QByteArray &newSalt, const QByteArray &
|
||||
}
|
||||
|
||||
void PasscodeBox::prepare() {
|
||||
addButton(langFactory(_turningOff ? lng_passcode_remove_button : lng_settings_save), [this] { onSave(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(langFactory(_turningOff ? lng_passcode_remove_button : lng_settings_save), [=] { save(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
_about.setRichText(st::passcodeTextStyle, lang(_cloudPwd ? lng_cloud_password_about : lng_passcode_about));
|
||||
_aboutHeight = _about.countHeight(st::boxWidth - st::boxPadding.left() * 1.5);
|
||||
@@ -65,19 +65,20 @@ void PasscodeBox::prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
connect(_oldPasscode, SIGNAL(changed()), this, SLOT(onOldChanged()));
|
||||
connect(_newPasscode, SIGNAL(changed()), this, SLOT(onNewChanged()));
|
||||
connect(_reenterPasscode, SIGNAL(changed()), this, SLOT(onNewChanged()));
|
||||
connect(_passwordHint, SIGNAL(changed()), this, SLOT(onNewChanged()));
|
||||
connect(_recoverEmail, SIGNAL(changed()), this, SLOT(onEmailChanged()));
|
||||
connect(_oldPasscode, &Ui::MaskedInputField::changed, [=] { oldChanged(); });
|
||||
connect(_newPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); });
|
||||
connect(_reenterPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); });
|
||||
connect(_passwordHint, &Ui::InputField::changed, [=] { newChanged(); });
|
||||
connect(_recoverEmail, &Ui::InputField::changed, [=] { emailChanged(); });
|
||||
|
||||
connect(_oldPasscode, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_newPasscode, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_reenterPasscode, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_passwordHint, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_recoverEmail, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
const auto fieldSubmit = [=] { submit(); };
|
||||
connect(_oldPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
|
||||
connect(_newPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
|
||||
connect(_reenterPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
|
||||
connect(_passwordHint, &Ui::InputField::submitted, fieldSubmit);
|
||||
connect(_recoverEmail, &Ui::InputField::submitted, fieldSubmit);
|
||||
|
||||
connect(_recover, SIGNAL(clicked()), this, SLOT(onRecoverByEmail()));
|
||||
_recover->addClickHandler([=] { recoverByEmail(); });
|
||||
|
||||
bool has = _cloudPwd ? (!_curSalt.isEmpty()) : Global::LocalPasscode();
|
||||
_oldPasscode->setVisible(_turningOff || has);
|
||||
@@ -88,11 +89,11 @@ void PasscodeBox::prepare() {
|
||||
_recoverEmail->setVisible(!_turningOff && _cloudPwd && _curSalt.isEmpty());
|
||||
}
|
||||
|
||||
void PasscodeBox::onSubmit() {
|
||||
void PasscodeBox::submit() {
|
||||
bool has = _cloudPwd ? (!_curSalt.isEmpty()) : Global::LocalPasscode();
|
||||
if (_oldPasscode->hasFocus()) {
|
||||
if (_turningOff) {
|
||||
onSave();
|
||||
save();
|
||||
} else {
|
||||
_newPasscode->setFocus();
|
||||
}
|
||||
@@ -110,16 +111,16 @@ void PasscodeBox::onSubmit() {
|
||||
} else if (!_passwordHint->isHidden()) {
|
||||
_passwordHint->setFocus();
|
||||
} else {
|
||||
onSave();
|
||||
save();
|
||||
}
|
||||
} else if (_passwordHint->hasFocus()) {
|
||||
if (_recoverEmail->isHidden()) {
|
||||
onSave();
|
||||
save();
|
||||
} else {
|
||||
_recoverEmail->setFocus();
|
||||
}
|
||||
} else if (_recoverEmail->hasFocus()) {
|
||||
onSave();
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +227,7 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) {
|
||||
emit reloadPassword();
|
||||
closeBox();
|
||||
} else {
|
||||
onBadOldPasscode();
|
||||
badOldPasscode();
|
||||
}
|
||||
} else if (err == qstr("NEW_PASSWORD_BAD")) {
|
||||
_newPasscode->setFocus();
|
||||
@@ -248,7 +249,7 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void PasscodeBox::onSave(bool force) {
|
||||
void PasscodeBox::save(bool force) {
|
||||
if (_setRequest) return;
|
||||
|
||||
QString old = _oldPasscode->text(), pwd = _newPasscode->text(), conf = _reenterPasscode->text();
|
||||
@@ -268,7 +269,7 @@ void PasscodeBox::onSave(bool force) {
|
||||
} else {
|
||||
cSetPasscodeBadTries(cPasscodeBadTries() + 1);
|
||||
cSetPasscodeLastTry(getms(true));
|
||||
onBadOldPasscode();
|
||||
badOldPasscode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -306,7 +307,7 @@ void PasscodeBox::onSave(bool force) {
|
||||
if (!_recoverEmail->isHidden() && email.isEmpty() && !force) {
|
||||
_skipEmailWarning = true;
|
||||
_replacedBy = Ui::show(Box<ConfirmBox>(lang(lng_cloud_password_about_recover), lang(lng_cloud_password_skip_email), st::attentionBoxButton, base::lambda_guarded(this, [this] {
|
||||
onSave(true);
|
||||
save(true);
|
||||
})), LayerOption::KeepOther);
|
||||
} else {
|
||||
QByteArray newPasswordData = pwd.isEmpty() ? QByteArray() : (_newSalt + pwd.toUtf8() + _newSalt);
|
||||
@@ -337,7 +338,7 @@ void PasscodeBox::onSave(bool force) {
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::onBadOldPasscode() {
|
||||
void PasscodeBox::badOldPasscode() {
|
||||
_oldPasscode->selectAll();
|
||||
_oldPasscode->setFocus();
|
||||
_oldPasscode->showError();
|
||||
@@ -348,7 +349,7 @@ void PasscodeBox::onBadOldPasscode() {
|
||||
update();
|
||||
}
|
||||
|
||||
void PasscodeBox::onOldChanged() {
|
||||
void PasscodeBox::oldChanged() {
|
||||
if (!_oldError.isEmpty()) {
|
||||
_oldError = QString();
|
||||
if (_hasRecovery && _hintText.isEmpty()) {
|
||||
@@ -358,21 +359,21 @@ void PasscodeBox::onOldChanged() {
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::onNewChanged() {
|
||||
void PasscodeBox::newChanged() {
|
||||
if (!_newError.isEmpty()) {
|
||||
_newError = QString();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::onEmailChanged() {
|
||||
void PasscodeBox::emailChanged() {
|
||||
if (!_emailError.isEmpty()) {
|
||||
_emailError = QString();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::onRecoverByEmail() {
|
||||
void PasscodeBox::recoverByEmail() {
|
||||
if (_pattern.isEmpty()) {
|
||||
_pattern = "-";
|
||||
MTP::send(MTPauth_RequestPasswordRecovery(), rpcDone(&PasscodeBox::recoverStarted), rpcFail(&PasscodeBox::recoverStartFail));
|
||||
@@ -381,18 +382,19 @@ void PasscodeBox::onRecoverByEmail() {
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::onRecoverExpired() {
|
||||
void PasscodeBox::recoverExpired() {
|
||||
_pattern = QString();
|
||||
}
|
||||
|
||||
void PasscodeBox::recover() {
|
||||
if (_pattern == "-") return;
|
||||
|
||||
_replacedBy = Ui::show(
|
||||
const auto box = Ui::show(
|
||||
Box<RecoverBox>(_pattern),
|
||||
LayerOption::KeepOther);
|
||||
connect(_replacedBy, SIGNAL(reloadPassword()), this, SIGNAL(reloadPassword()));
|
||||
connect(_replacedBy, SIGNAL(recoveryExpired()), this, SLOT(onRecoverExpired()));
|
||||
connect(box, &RecoverBox::reloadPassword, this, &PasscodeBox::reloadPassword);
|
||||
connect(box, &RecoverBox::recoveryExpired, this, &PasscodeBox::recoverExpired);
|
||||
_replacedBy = box;
|
||||
}
|
||||
|
||||
void PasscodeBox::recoverStarted(const MTPauth_PasswordRecovery &result) {
|
||||
@@ -416,13 +418,13 @@ RecoverBox::RecoverBox(QWidget*, const QString &pattern)
|
||||
void RecoverBox::prepare() {
|
||||
setTitle(langFactory(lng_signin_recover_title));
|
||||
|
||||
addButton(langFactory(lng_passcode_submit), [this] { onSubmit(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_passcode_submit), [=] { submit(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine + _recoverCode->height() + st::passcodeTextLine);
|
||||
|
||||
connect(_recoverCode, SIGNAL(changed()), this, SLOT(onCodeChanged()));
|
||||
connect(_recoverCode, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_recoverCode, &Ui::InputField::changed, [=] { codeChanged(); });
|
||||
connect(_recoverCode, &Ui::InputField::submitted, [=] { submit(); });
|
||||
}
|
||||
|
||||
void RecoverBox::paintEvent(QPaintEvent *e) {
|
||||
@@ -452,7 +454,7 @@ void RecoverBox::setInnerFocus() {
|
||||
_recoverCode->setFocusFast();
|
||||
}
|
||||
|
||||
void RecoverBox::onSubmit() {
|
||||
void RecoverBox::submit() {
|
||||
if (_submitRequest) return;
|
||||
|
||||
QString code = _recoverCode->getLastText().trimmed();
|
||||
@@ -465,7 +467,7 @@ void RecoverBox::onSubmit() {
|
||||
_submitRequest = MTP::send(MTPauth_RecoverPassword(MTP_string(code)), rpcDone(&RecoverBox::codeSubmitDone, true), rpcFail(&RecoverBox::codeSubmitFail));
|
||||
}
|
||||
|
||||
void RecoverBox::onCodeChanged() {
|
||||
void RecoverBox::codeChanged() {
|
||||
_error = QString();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -22,16 +22,6 @@ public:
|
||||
PasscodeBox(QWidget*, bool turningOff);
|
||||
PasscodeBox(QWidget*, const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, const QString &hint, bool turningOff = false);
|
||||
|
||||
private slots:
|
||||
void onSave(bool force = false);
|
||||
void onBadOldPasscode();
|
||||
void onOldChanged();
|
||||
void onNewChanged();
|
||||
void onEmailChanged();
|
||||
void onRecoverByEmail();
|
||||
void onRecoverExpired();
|
||||
void onSubmit();
|
||||
|
||||
signals:
|
||||
void reloadPassword();
|
||||
|
||||
@@ -43,7 +33,15 @@ protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
void submit();
|
||||
void closeReplacedBy();
|
||||
void oldChanged();
|
||||
void newChanged();
|
||||
void emailChanged();
|
||||
void save(bool force = false);
|
||||
void badOldPasscode();
|
||||
void recoverByEmail();
|
||||
void recoverExpired();
|
||||
|
||||
void setPasswordDone(const MTPBool &result);
|
||||
bool setPasswordFail(const RPCError &error);
|
||||
@@ -84,10 +82,6 @@ class RecoverBox : public BoxContent, public RPCSender {
|
||||
public:
|
||||
RecoverBox(QWidget*, const QString &pattern);
|
||||
|
||||
public slots:
|
||||
void onSubmit();
|
||||
void onCodeChanged();
|
||||
|
||||
signals:
|
||||
void reloadPassword();
|
||||
void recoveryExpired();
|
||||
@@ -100,6 +94,8 @@ protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
void submit();
|
||||
void codeChanged();
|
||||
void codeSubmitDone(bool recover, const MTPauth_Authorization &result);
|
||||
bool codeSubmitFail(const RPCError &error);
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ void PeerListBox::createMultiSelect() {
|
||||
) | rpl::start_with_next(
|
||||
[this] { updateScrollSkips(); },
|
||||
lifetime());
|
||||
_select->entity()->setSubmittedCallback([this](bool chtrlShiftEnter) { content()->submitted(); });
|
||||
_select->entity()->setSubmittedCallback([this](Qt::KeyboardModifiers) { content()->submitted(); });
|
||||
_select->entity()->setQueryChangedCallback([this](const QString &query) { searchQueryChanged(query); });
|
||||
_select->entity()->setItemRemovedCallback([this](uint64 itemId) {
|
||||
if (auto peer = App::peerLoaded(itemId)) {
|
||||
|
||||
@@ -308,7 +308,7 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
|
||||
QObject::connect(
|
||||
result->entity(),
|
||||
&Ui::InputField::submitted,
|
||||
[this] { submitTitle(); });
|
||||
[=] { submitTitle(); });
|
||||
|
||||
_controls.title = result->entity();
|
||||
return std::move(result);
|
||||
@@ -339,7 +339,7 @@ object_ptr<Ui::RpWidget> Controller::createDescriptionEdit() {
|
||||
QObject::connect(
|
||||
result->entity(),
|
||||
&Ui::InputField::submitted,
|
||||
[this] { submitDescription(); });
|
||||
[=] { submitDescription(); });
|
||||
|
||||
_controls.description = result->entity();
|
||||
return std::move(result);
|
||||
|
||||
@@ -60,7 +60,7 @@ void RateCallBox::ratingChanged(int value) {
|
||||
Expects(value > 0 && value <= kMaxRating);
|
||||
if (!_rating) {
|
||||
clearButtons();
|
||||
addButton(langFactory(lng_send_button), [this] { onSend(); });
|
||||
addButton(langFactory(lng_send_button), [this] { send(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
}
|
||||
_rating = value;
|
||||
@@ -82,9 +82,9 @@ void RateCallBox::ratingChanged(int value) {
|
||||
_comment->resize(width() - (st::callRatingPadding.left() + st::callRatingPadding.right()), _comment->height());
|
||||
|
||||
updateMaxHeight();
|
||||
connect(_comment, SIGNAL(resized()), this, SLOT(onCommentResized()));
|
||||
connect(_comment, SIGNAL(submitted(bool)), this, SLOT(onSend()));
|
||||
connect(_comment, SIGNAL(cancelled()), this, SLOT(onClose()));
|
||||
connect(_comment, &Ui::InputField::resized, [=] { commentResized(); });
|
||||
connect(_comment, &Ui::InputField::submitted, [=] { send(); });
|
||||
connect(_comment, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
}
|
||||
_comment->setFocusFast();
|
||||
} else if (_comment) {
|
||||
@@ -101,13 +101,14 @@ void RateCallBox::setInnerFocus() {
|
||||
}
|
||||
}
|
||||
|
||||
void RateCallBox::onCommentResized() {
|
||||
void RateCallBox::commentResized() {
|
||||
updateMaxHeight();
|
||||
update();
|
||||
}
|
||||
|
||||
void RateCallBox::onSend() {
|
||||
void RateCallBox::send() {
|
||||
Expects(_rating > 0 && _rating <= kMaxRating);
|
||||
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -17,18 +17,9 @@ class IconButton;
|
||||
} // namespace Ui
|
||||
|
||||
class RateCallBox : public BoxContent, private MTP::Sender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RateCallBox(QWidget*, uint64 callId, uint64 callAccessHash);
|
||||
|
||||
private slots:
|
||||
void onSend();
|
||||
void onCommentResized();
|
||||
void onClose() {
|
||||
closeBox();
|
||||
}
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
void setInnerFocus() override;
|
||||
@@ -38,6 +29,8 @@ protected:
|
||||
private:
|
||||
void updateMaxHeight();
|
||||
void ratingChanged(int value);
|
||||
void send();
|
||||
void commentResized();
|
||||
|
||||
uint64 _callId = 0;
|
||||
uint64 _callAccessHash = 0;
|
||||
|
||||
@@ -39,8 +39,8 @@ void ReportBox::prepare() {
|
||||
}
|
||||
}()));
|
||||
|
||||
addButton(langFactory(lng_report_button), [this] { onReport(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_report_button), [=] { report(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
_reasonGroup = std::make_shared<Ui::RadioenumGroup<Reason>>(
|
||||
Reason::Spam);
|
||||
@@ -93,9 +93,9 @@ void ReportBox::reasonChanged(Reason reason) {
|
||||
_reasonOtherText->resize(width() - (st::boxPadding.left() + st::boxOptionListPadding.left() + st::boxPadding.right()), _reasonOtherText->height());
|
||||
|
||||
updateMaxHeight();
|
||||
connect(_reasonOtherText, SIGNAL(resized()), this, SLOT(onReasonResized()));
|
||||
connect(_reasonOtherText, SIGNAL(submitted(bool)), this, SLOT(onReport()));
|
||||
connect(_reasonOtherText, SIGNAL(cancelled()), this, SLOT(onClose()));
|
||||
connect(_reasonOtherText, &Ui::InputField::resized, [=] { reasonResized(); });
|
||||
connect(_reasonOtherText, &Ui::InputField::submitted, [=] { report(); });
|
||||
connect(_reasonOtherText, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
}
|
||||
_reasonOtherText->setFocusFast();
|
||||
} else if (_reasonOtherText) {
|
||||
@@ -112,12 +112,12 @@ void ReportBox::setInnerFocus() {
|
||||
}
|
||||
}
|
||||
|
||||
void ReportBox::onReasonResized() {
|
||||
void ReportBox::reasonResized() {
|
||||
updateMaxHeight();
|
||||
update();
|
||||
}
|
||||
|
||||
void ReportBox::onReport() {
|
||||
void ReportBox::report() {
|
||||
if (_requestId) return;
|
||||
|
||||
if (_reasonOtherText && _reasonOtherText->getLastText().trimmed().isEmpty()) {
|
||||
|
||||
@@ -18,19 +18,10 @@ class InputField;
|
||||
} // namespace Ui
|
||||
|
||||
class ReportBox : public BoxContent, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ReportBox(QWidget*, not_null<PeerData*> peer);
|
||||
ReportBox(QWidget*, not_null<PeerData*> peer, MessageIdsList ids);
|
||||
|
||||
private slots:
|
||||
void onReport();
|
||||
void onReasonResized();
|
||||
void onClose() {
|
||||
closeBox();
|
||||
}
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
void setInnerFocus() override;
|
||||
@@ -45,7 +36,9 @@ private:
|
||||
Other,
|
||||
};
|
||||
void reasonChanged(Reason reason);
|
||||
void reasonResized();
|
||||
void updateMaxHeight();
|
||||
void report();
|
||||
|
||||
void reportDone(const MTPBool &result);
|
||||
bool reportFail(const RPCError &error);
|
||||
|
||||
@@ -1319,10 +1319,12 @@ void SendFilesBox::AlbumPreview::mouseReleaseEvent(QMouseEvent *e) {
|
||||
|
||||
SendFilesBox::SendFilesBox(
|
||||
QWidget*,
|
||||
not_null<Window::Controller*> controller,
|
||||
Storage::PreparedList &&list,
|
||||
const TextWithTags &caption,
|
||||
CompressConfirm compressed)
|
||||
: _list(std::move(list))
|
||||
: _controller(controller)
|
||||
, _list(std::move(list))
|
||||
, _compressConfirmInitial(compressed)
|
||||
, _compressConfirm(compressed)
|
||||
, _caption(
|
||||
@@ -1556,17 +1558,18 @@ void SendFilesBox::applyAlbumOrder() {
|
||||
void SendFilesBox::setupCaption() {
|
||||
_caption->setMaxLength(MaxPhotoCaption);
|
||||
_caption->setSubmitSettings(Ui::InputField::SubmitSettings::Both);
|
||||
connect(_caption, &Ui::InputField::resized, this, [this] {
|
||||
connect(_caption, &Ui::InputField::resized, [=] {
|
||||
captionResized();
|
||||
});
|
||||
connect(_caption, &Ui::InputField::submitted, this, [this](
|
||||
bool ctrlShiftEnter) {
|
||||
connect(_caption, &Ui::InputField::submitted, [=](
|
||||
Qt::KeyboardModifiers modifiers) {
|
||||
const auto ctrlShiftEnter = modifiers.testFlag(Qt::ShiftModifier)
|
||||
&& (modifiers.testFlag(Qt::ControlModifier)
|
||||
|| modifiers.testFlag(Qt::MetaModifier));
|
||||
send(ctrlShiftEnter);
|
||||
});
|
||||
connect(_caption, &Ui::InputField::cancelled, this, [this] {
|
||||
closeBox();
|
||||
});
|
||||
_caption->setMimeDataHook([this](
|
||||
connect(_caption, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
_caption->setMimeDataHook([=](
|
||||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
@@ -1578,7 +1581,9 @@ void SendFilesBox::setupCaption() {
|
||||
});
|
||||
_caption->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
_caption->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
_caption->setMarkdownReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
_caption->setMarkdownReplacesEnabled(rpl::single(true));
|
||||
_caption->setEditLinkCallback(
|
||||
DefaultEditLinkCallback(_controller, _caption));
|
||||
}
|
||||
|
||||
void SendFilesBox::captionResized() {
|
||||
@@ -1790,7 +1795,7 @@ void SendFilesBox::send(bool ctrlShiftEnter) {
|
||||
_confirmed = true;
|
||||
if (_confirmedCallback) {
|
||||
auto caption = _caption
|
||||
? _caption->getTextWithTags()
|
||||
? _caption->getTextWithAppliedMarkdown()
|
||||
: TextWithTags();
|
||||
_confirmedCallback(
|
||||
std::move(_list),
|
||||
|
||||
@@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "storage/localimageloader.h"
|
||||
#include "storage/storage_media_prepare.h"
|
||||
|
||||
namespace Window {
|
||||
class Controller;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
template <typename Enum>
|
||||
class Radioenum;
|
||||
@@ -32,6 +36,7 @@ class SendFilesBox : public BoxContent {
|
||||
public:
|
||||
SendFilesBox(
|
||||
QWidget*,
|
||||
not_null<Window::Controller*> controller,
|
||||
Storage::PreparedList &&list,
|
||||
const TextWithTags &caption,
|
||||
CompressConfirm compressed);
|
||||
@@ -88,6 +93,8 @@ private:
|
||||
bool canAddUrls(const QList<QUrl> &urls) const;
|
||||
bool addFiles(not_null<const QMimeData*> data);
|
||||
|
||||
not_null<Window::Controller*> _controller;
|
||||
|
||||
QString _titleText;
|
||||
int _titleHeight = 0;
|
||||
|
||||
|
||||
@@ -61,7 +61,14 @@ void ShareBox::prepare() {
|
||||
}
|
||||
});
|
||||
_select->setResizedCallback([this] { updateScrollSkips(); });
|
||||
_select->setSubmittedCallback([this](bool) { _inner->onSelectActive(); });
|
||||
_select->setSubmittedCallback([this](Qt::KeyboardModifiers modifiers) {
|
||||
if (modifiers.testFlag(Qt::ControlModifier)
|
||||
|| modifiers.testFlag(Qt::MetaModifier)) {
|
||||
onSubmit();
|
||||
} else {
|
||||
_inner->onSelectActive();
|
||||
}
|
||||
});
|
||||
connect(_inner, SIGNAL(searchByUsername()), this, SLOT(onNeedSearchByUsername()));
|
||||
_inner->setPeerSelectedChangedCallback([this](PeerData *peer, bool checked) {
|
||||
onPeerSelectedChanged(peer, checked);
|
||||
|
||||
@@ -610,14 +610,14 @@ StickersBox::Inner::Inner(QWidget *parent, not_null<ChannelData*> megagroup) : T
|
||||
connect(
|
||||
_megagroupSetField,
|
||||
&Ui::MaskedInputField::changed,
|
||||
[this] {
|
||||
[=] {
|
||||
_megagroupSetAddressChangedTimer.callOnce(
|
||||
kHandleMegagroupSetAddressChangeTimeout);
|
||||
});
|
||||
connect(
|
||||
_megagroupSetField,
|
||||
&Ui::MaskedInputField::submitted,
|
||||
[this] {
|
||||
[=] {
|
||||
_megagroupSetAddressChangedTimer.cancel();
|
||||
handleMegagroupSetAddressChange();
|
||||
});
|
||||
|
||||
@@ -35,18 +35,18 @@ void UsernameBox::prepare() {
|
||||
|
||||
setTitle(langFactory(lng_username_title));
|
||||
|
||||
addButton(langFactory(lng_settings_save), [this] { onSave(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_settings_save), [=] { save(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
connect(_username, SIGNAL(changed()), this, SLOT(onChanged()));
|
||||
connect(_username, SIGNAL(submitted(bool)), this, SLOT(onSave()));
|
||||
connect(_link, SIGNAL(clicked()), this, SLOT(onLinkClick()));
|
||||
connect(_username, &Ui::MaskedInputField::changed, [=] { changed(); });
|
||||
connect(_username, &Ui::MaskedInputField::submitted, [=] { save(); });
|
||||
_link->addClickHandler([=] { linkClick(); });
|
||||
|
||||
_about.setRichText(st::usernameTextStyle, lang(lng_username_about));
|
||||
setDimensions(st::boxWidth, st::usernamePadding.top() + _username->height() + st::usernameSkip + _about.countHeight(st::boxWidth - st::usernamePadding.left()) + 3 * st::usernameTextStyle.lineHeight + st::usernamePadding.bottom());
|
||||
|
||||
_checkTimer->setSingleShot(true);
|
||||
connect(_checkTimer, SIGNAL(timeout()), this, SLOT(onCheck()));
|
||||
connect(_checkTimer, &QTimer::timeout, [=] { check(); });
|
||||
|
||||
updateLinkText();
|
||||
}
|
||||
@@ -96,14 +96,14 @@ void UsernameBox::resizeEvent(QResizeEvent *e) {
|
||||
_link->moveToLeft(st::usernamePadding.left(), linky + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2));
|
||||
}
|
||||
|
||||
void UsernameBox::onSave() {
|
||||
void UsernameBox::save() {
|
||||
if (_saveRequestId) return;
|
||||
|
||||
_sentUsername = getName();
|
||||
_saveRequestId = MTP::send(MTPaccount_UpdateUsername(MTP_string(_sentUsername)), rpcDone(&UsernameBox::onUpdateDone), rpcFail(&UsernameBox::onUpdateFail));
|
||||
}
|
||||
|
||||
void UsernameBox::onCheck() {
|
||||
void UsernameBox::check() {
|
||||
if (_checkRequestId) {
|
||||
MTP::cancel(_checkRequestId);
|
||||
}
|
||||
@@ -118,7 +118,7 @@ void UsernameBox::onCheck() {
|
||||
}
|
||||
}
|
||||
|
||||
void UsernameBox::onChanged() {
|
||||
void UsernameBox::changed() {
|
||||
updateLinkText();
|
||||
QString name = getName();
|
||||
if (name.isEmpty()) {
|
||||
@@ -156,7 +156,7 @@ void UsernameBox::onChanged() {
|
||||
}
|
||||
}
|
||||
|
||||
void UsernameBox::onLinkClick() {
|
||||
void UsernameBox::linkClick() {
|
||||
Application::clipboard()->setText(Messenger::Instance().createInternalLinkFull(getName()));
|
||||
Ui::Toast::Show(lang(lng_username_copied));
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@ class LinkButton;
|
||||
} // namespace Ui
|
||||
|
||||
class UsernameBox : public BoxContent, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UsernameBox(QWidget*);
|
||||
|
||||
@@ -27,14 +25,6 @@ protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private slots:
|
||||
void onSave();
|
||||
|
||||
void onCheck();
|
||||
void onChanged();
|
||||
|
||||
void onLinkClick();
|
||||
|
||||
private:
|
||||
void onUpdateDone(const MTPUser &result);
|
||||
bool onUpdateFail(const RPCError &error);
|
||||
@@ -42,6 +32,13 @@ private:
|
||||
void onCheckDone(const MTPBool &result);
|
||||
bool onCheckFail(const RPCError &error);
|
||||
|
||||
void save();
|
||||
|
||||
void check();
|
||||
void changed();
|
||||
|
||||
void linkClick();
|
||||
|
||||
QString getName() const;
|
||||
void updateLinkText();
|
||||
|
||||
|
||||
@@ -10,6 +10,14 @@ using "basic.style";
|
||||
using "ui/widgets/widgets.style";
|
||||
using "window/window.style";
|
||||
|
||||
CallSignalBars {
|
||||
width: pixels;
|
||||
radius: pixels;
|
||||
skip: pixels;
|
||||
color: color;
|
||||
inactiveOpacity: double;
|
||||
}
|
||||
|
||||
callWidth: 300px;
|
||||
callHeight: 470px;
|
||||
callShadow: Shadow {
|
||||
@@ -189,3 +197,16 @@ callDebugLabel: FlatLabel(defaultFlatLabel) {
|
||||
margin: callDebugPadding;
|
||||
}
|
||||
callPanelDuration: 150;
|
||||
|
||||
callPanelSignalBars: CallSignalBars {
|
||||
width: 3px;
|
||||
radius: 1px;
|
||||
skip: 1px;
|
||||
color: callNameFg;
|
||||
inactiveOpacity: 0.5;
|
||||
}
|
||||
callBarSignalBars: CallSignalBars(callPanelSignalBars) {
|
||||
color: callBarFg;
|
||||
}
|
||||
callSignalMargin: 8px;
|
||||
callSignalPadding: 4px;
|
||||
|
||||
@@ -558,6 +558,12 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||
const auto call = static_cast<Call*>(controller->implData);
|
||||
call->handleControllerStateChange(controller, state);
|
||||
};
|
||||
callbacks.signalBarCountChanged = [](
|
||||
tgvoip::VoIPController *controller,
|
||||
int count) {
|
||||
const auto call = static_cast<Call*>(controller->implData);
|
||||
call->handleControllerBarCountChange(controller, count);
|
||||
};
|
||||
|
||||
_controller.create();
|
||||
if (_mute) {
|
||||
@@ -584,9 +590,12 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||
_controller->Connect();
|
||||
}
|
||||
|
||||
void Call::handleControllerStateChange(tgvoip::VoIPController *controller, int state) {
|
||||
void Call::handleControllerStateChange(
|
||||
tgvoip::VoIPController *controller,
|
||||
int state) {
|
||||
// NB! Can be called from an arbitrary thread!
|
||||
// Expects(controller == _controller.get()); This can be called from ~VoIPController()!
|
||||
// This can be called from ~VoIPController()!
|
||||
// Expects(controller == _controller.get());
|
||||
Expects(controller->implData == static_cast<void*>(this));
|
||||
|
||||
switch (state) {
|
||||
@@ -615,6 +624,26 @@ void Call::handleControllerStateChange(tgvoip::VoIPController *controller, int s
|
||||
}
|
||||
}
|
||||
|
||||
void Call::handleControllerBarCountChange(
|
||||
tgvoip::VoIPController *controller,
|
||||
int count) {
|
||||
// NB! Can be called from an arbitrary thread!
|
||||
// This can be called from ~VoIPController()!
|
||||
// Expects(controller == _controller.get());
|
||||
Expects(controller->implData == static_cast<void*>(this));
|
||||
|
||||
InvokeQueued(this, [=] {
|
||||
setSignalBarCount(count);
|
||||
});
|
||||
}
|
||||
|
||||
void Call::setSignalBarCount(int count) {
|
||||
if (_signalBarCount != count) {
|
||||
_signalBarCount = count;
|
||||
_signalBarCountChanged.notify(count);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Call::checkCallCommonFields(const T &call) {
|
||||
auto checkFailed = [this] {
|
||||
@@ -708,6 +737,9 @@ void Call::setState(State state) {
|
||||
|
||||
void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
|
||||
Expects(type != FinishType::None);
|
||||
|
||||
setSignalBarCount(kSignalBarFinished);
|
||||
|
||||
auto finalState = (type == FinishType::Ended) ? State::Ended : State::Failed;
|
||||
auto hangupState = (type == FinishType::Ended) ? State::HangingUp : State::FailedHangingUp;
|
||||
if (_state == State::Requesting) {
|
||||
@@ -742,11 +774,15 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
|
||||
}
|
||||
|
||||
void Call::setStateQueued(State state) {
|
||||
InvokeQueued(this, [this, state] { setState(state); });
|
||||
InvokeQueued(this, [=] {
|
||||
setState(state);
|
||||
});
|
||||
}
|
||||
|
||||
void Call::setFailedQueued(int error) {
|
||||
InvokeQueued(this, [this, error] { handleControllerError(error); });
|
||||
InvokeQueued(this, [=] {
|
||||
handleControllerError(error);
|
||||
});
|
||||
}
|
||||
|
||||
void Call::handleRequestError(const RPCError &error) {
|
||||
@@ -778,6 +814,7 @@ void Call::destroyController() {
|
||||
_controller.reset();
|
||||
DEBUG_LOG(("Call Info: Call controller destroyed."));
|
||||
}
|
||||
setSignalBarCount(kSignalBarFinished);
|
||||
}
|
||||
|
||||
Call::~Call() {
|
||||
|
||||
@@ -93,6 +93,13 @@ public:
|
||||
return _stateChanged;
|
||||
}
|
||||
|
||||
static constexpr auto kSignalBarStarting = -1;
|
||||
static constexpr auto kSignalBarFinished = -2;
|
||||
static constexpr auto kSignalBarCount = 4;
|
||||
base::Observable<int> &signalBarCountChanged() {
|
||||
return _signalBarCountChanged;
|
||||
}
|
||||
|
||||
void setMute(bool mute);
|
||||
bool isMute() const {
|
||||
return _mute;
|
||||
@@ -146,7 +153,12 @@ private:
|
||||
void startWaitingTrack();
|
||||
|
||||
void generateModExpFirst(base::const_byte_span randomSeed);
|
||||
void handleControllerStateChange(tgvoip::VoIPController *controller, int state);
|
||||
void handleControllerStateChange(
|
||||
tgvoip::VoIPController *controller,
|
||||
int state);
|
||||
void handleControllerBarCountChange(
|
||||
tgvoip::VoIPController *controller,
|
||||
int count);
|
||||
void createAndStartController(const MTPDphoneCall &call);
|
||||
|
||||
template <typename T>
|
||||
@@ -159,6 +171,7 @@ private:
|
||||
void setState(State state);
|
||||
void setStateQueued(State state);
|
||||
void setFailedQueued(int error);
|
||||
void setSignalBarCount(int count);
|
||||
void destroyController();
|
||||
|
||||
not_null<Delegate*> _delegate;
|
||||
@@ -168,6 +181,8 @@ private:
|
||||
FinishType _finishAfterRequestingCall = FinishType::None;
|
||||
bool _answerAfterDhConfigReceived = false;
|
||||
base::Observable<State> _stateChanged;
|
||||
int _signalBarCount = kSignalBarStarting;
|
||||
base::Observable<int> _signalBarCountChanged;
|
||||
TimeMs _startTime = 0;
|
||||
base::DelayedCallTimer _finishByTimeoutTimer;
|
||||
base::Timer _discardByTimeoutTimer;
|
||||
|
||||
@@ -67,6 +67,66 @@ private:
|
||||
|
||||
};
|
||||
|
||||
SignalBars::SignalBars(
|
||||
QWidget *parent,
|
||||
not_null<Call*> call,
|
||||
const style::CallSignalBars &st,
|
||||
base::lambda<void()> displayedChangedCallback)
|
||||
: RpWidget(parent)
|
||||
, _st(st)
|
||||
, _displayedChangedCallback(std::move(displayedChangedCallback)) {
|
||||
resize(
|
||||
_st.width + (_st.width + _st.skip) * (Call::kSignalBarCount - 1),
|
||||
_st.width * Call::kSignalBarCount);
|
||||
subscribe(call->signalBarCountChanged(), [=](int count) {
|
||||
changed(count);
|
||||
});
|
||||
}
|
||||
|
||||
bool SignalBars::isDisplayed() const {
|
||||
return (_count >= 0);
|
||||
}
|
||||
|
||||
void SignalBars::paintEvent(QPaintEvent *e) {
|
||||
if (!isDisplayed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Painter p(this);
|
||||
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(_st.color);
|
||||
for (auto i = 0; i < Call::kSignalBarCount; ++i) {
|
||||
p.setOpacity((i < _count) ? 1. : _st.inactiveOpacity);
|
||||
const auto barHeight = (i + 1) * _st.width;
|
||||
const auto barLeft = i * (_st.width + _st.skip);
|
||||
const auto barTop = height() - barHeight;
|
||||
p.drawRoundedRect(
|
||||
barLeft,
|
||||
barTop,
|
||||
_st.width,
|
||||
barHeight,
|
||||
_st.radius,
|
||||
_st.radius);
|
||||
}
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
|
||||
void SignalBars::changed(int count) {
|
||||
if (_count == Call::kSignalBarFinished) {
|
||||
return;
|
||||
}
|
||||
if (_count != count) {
|
||||
const auto wasDisplayed = isDisplayed();
|
||||
_count = count;
|
||||
if (isDisplayed() != wasDisplayed && _displayedChangedCallback) {
|
||||
_displayedChangedCallback();
|
||||
}
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
Panel::Button::Button(QWidget *parent, const style::CallButton &stFrom, const style::CallButton *stTo) : Ui::RippleButton(parent, stFrom.button.ripple)
|
||||
, _stFrom(&stFrom)
|
||||
, _stTo(stTo) {
|
||||
@@ -238,7 +298,8 @@ Panel::Panel(not_null<Call*> call)
|
||||
, _cancel(this, object_ptr<Button>(this, st::callCancel))
|
||||
, _mute(this, st::callMuteToggle)
|
||||
, _name(this, st::callName)
|
||||
, _status(this, st::callStatus) {
|
||||
, _status(this, st::callStatus)
|
||||
, _signalBars(this, call, st::callPanelSignalBars) {
|
||||
_decline->setDuration(st::callPanelDuration);
|
||||
_cancel->setDuration(st::callPanelDuration);
|
||||
|
||||
@@ -337,10 +398,18 @@ void Panel::initControls() {
|
||||
void Panel::reinitControls() {
|
||||
Expects(_call != nullptr);
|
||||
|
||||
unsubscribe(_stateChangedSubscription);
|
||||
_stateChangedSubscription = subscribe(_call->stateChanged(), [this](State state) { stateChanged(state); });
|
||||
unsubscribe(base::take(_stateChangedSubscription));
|
||||
_stateChangedSubscription = subscribe(
|
||||
_call->stateChanged(),
|
||||
[=](State state) { stateChanged(state); });
|
||||
stateChanged(_call->state());
|
||||
|
||||
_signalBars.create(
|
||||
this,
|
||||
_call,
|
||||
st::callPanelSignalBars,
|
||||
[=] { rtlupdate(signalBarsRect()); });
|
||||
|
||||
_name->setText(App::peerName(_call->user()));
|
||||
updateStatusText(_call->state());
|
||||
}
|
||||
@@ -585,6 +654,12 @@ void Panel::updateControlsGeometry() {
|
||||
updateHangupGeometry();
|
||||
|
||||
_mute->moveToRight(_padding.right() + st::callMuteRight, controlsTop);
|
||||
|
||||
const auto skip = st::callSignalMargin + st::callSignalPadding;
|
||||
const auto delta = (_signalBars->width() - _signalBars->height());
|
||||
_signalBars->moveToLeft(
|
||||
_padding.left() + skip,
|
||||
_padding.top() + skip + delta / 2);
|
||||
}
|
||||
|
||||
void Panel::updateHangupGeometry() {
|
||||
@@ -637,6 +712,10 @@ void Panel::paintEvent(QPaintEvent *e) {
|
||||
p.fillRect(0, _contentTop, width(), height() - _contentTop, brush);
|
||||
}
|
||||
|
||||
if (_signalBars->isDisplayed()) {
|
||||
paintSignalBarsBg(p);
|
||||
}
|
||||
|
||||
if (!_fingerprint.empty()) {
|
||||
App::roundRect(p, _fingerprintArea, st::callFingerprintBg, ImageRoundRadius::Small);
|
||||
|
||||
@@ -651,6 +730,23 @@ void Panel::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
QRect Panel::signalBarsRect() const {
|
||||
const auto size = 2 * st::callSignalPadding + _signalBars->width();
|
||||
return QRect(
|
||||
_padding.left() + st::callSignalMargin,
|
||||
_padding.top() + st::callSignalMargin,
|
||||
size,
|
||||
size);
|
||||
}
|
||||
|
||||
void Panel::paintSignalBarsBg(Painter &p) {
|
||||
App::roundRect(
|
||||
p,
|
||||
signalBarsRect(),
|
||||
st::callFingerprintBg,
|
||||
ImageRoundRadius::Small);
|
||||
}
|
||||
|
||||
void Panel::closeEvent(QCloseEvent *e) {
|
||||
if (_call) {
|
||||
_call->hangup();
|
||||
|
||||
@@ -20,8 +20,34 @@ template <typename Widget>
|
||||
class FadeWrap;
|
||||
} // namespace Ui
|
||||
|
||||
namespace style {
|
||||
struct CallSignalBars;
|
||||
} // namespace style
|
||||
|
||||
namespace Calls {
|
||||
|
||||
class SignalBars : public Ui::RpWidget, private base::Subscriber {
|
||||
public:
|
||||
SignalBars(
|
||||
QWidget *parent,
|
||||
not_null<Call*> call,
|
||||
const style::CallSignalBars &st,
|
||||
base::lambda<void()> displayedChangedCallback = nullptr);
|
||||
|
||||
bool isDisplayed() const;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
void changed(int count);
|
||||
|
||||
const style::CallSignalBars &_st;
|
||||
int _count = Call::kSignalBarStarting;
|
||||
base::lambda<void()> _displayedChangedCallback;
|
||||
|
||||
};
|
||||
|
||||
class Panel
|
||||
: public Ui::RpWidget
|
||||
, private base::Subscriber
|
||||
@@ -67,6 +93,8 @@ private:
|
||||
void refreshUserPhoto();
|
||||
bool isGoodUserPhoto(PhotoData *photo);
|
||||
void createUserpicCache(ImagePtr image);
|
||||
QRect signalBarsRect() const;
|
||||
void paintSignalBarsBg(Painter &p);
|
||||
|
||||
void updateControlsGeometry();
|
||||
void updateHangupGeometry();
|
||||
@@ -102,6 +130,7 @@ private:
|
||||
object_ptr<Ui::IconButton> _mute;
|
||||
object_ptr<Ui::FlatLabel> _name;
|
||||
object_ptr<Ui::FlatLabel> _status;
|
||||
object_ptr<SignalBars> _signalBars;
|
||||
std::vector<EmojiPtr> _fingerprint;
|
||||
QRect _fingerprintArea;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "calls/calls_call.h"
|
||||
#include "calls/calls_instance.h"
|
||||
#include "calls/calls_panel.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "observer_peer.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
@@ -75,6 +76,7 @@ TopBar::TopBar(
|
||||
: RpWidget(parent)
|
||||
, _call(call)
|
||||
, _durationLabel(this, st::callBarLabel)
|
||||
, _signalBars(this, _call.get(), st::callBarSignalBars)
|
||||
, _fullInfoLabel(this, st::callBarInfoLabel)
|
||||
, _shortInfoLabel(this, st::callBarInfoLabel)
|
||||
, _hangupLabel(this, st::callBarLabel, lang(lng_call_bar_hangup).toUpper())
|
||||
@@ -169,14 +171,23 @@ void TopBar::resizeEvent(QResizeEvent *e) {
|
||||
|
||||
void TopBar::updateControlsGeometry() {
|
||||
auto left = 0;
|
||||
_mute->moveToLeft(left, 0); left += _mute->width();
|
||||
_durationLabel->moveToLeft(left, st::callBarLabelTop); left += _durationLabel->width() + st::callBarSkip;
|
||||
_mute->moveToLeft(left, 0);
|
||||
left += _mute->width();
|
||||
_durationLabel->moveToLeft(left, st::callBarLabelTop);
|
||||
left += _durationLabel->width() + st::callBarSkip;
|
||||
_signalBars->moveToLeft(left, (height() - _signalBars->height()) / 2);
|
||||
left += _signalBars->width() + st::callBarSkip;
|
||||
|
||||
auto right = st::callBarRightSkip;
|
||||
_hangupLabel->moveToRight(right, st::callBarLabelTop); right += _hangupLabel->width();
|
||||
_hangupLabel->moveToRight(right, st::callBarLabelTop);
|
||||
right += _hangupLabel->width();
|
||||
right += st::callBarHangup.width;
|
||||
_hangup->setGeometryToRight(0, 0, right, height());
|
||||
_info->setGeometryToLeft(_mute->width(), 0, width() - _mute->width() - _hangup->width(), height());
|
||||
_info->setGeometryToLeft(
|
||||
_mute->width(),
|
||||
0,
|
||||
width() - _mute->width() - _hangup->width(),
|
||||
height());
|
||||
|
||||
auto fullWidth = _fullInfoLabel->naturalWidth();
|
||||
auto showFull = (left + fullWidth + right <= width());
|
||||
|
||||
@@ -21,6 +21,7 @@ class FlatLabel;
|
||||
namespace Calls {
|
||||
|
||||
class Call;
|
||||
class SignalBars;
|
||||
|
||||
class TopBar : public Ui::RpWidget, private base::Subscriber {
|
||||
public:
|
||||
@@ -45,6 +46,7 @@ private:
|
||||
|
||||
bool _muted = false;
|
||||
object_ptr<Ui::LabelSimple> _durationLabel;
|
||||
object_ptr<SignalBars> _signalBars;
|
||||
object_ptr<Ui::FlatLabel> _fullInfoLabel;
|
||||
object_ptr<Ui::FlatLabel> _shortInfoLabel;
|
||||
object_ptr<Ui::LabelSimple> _hangupLabel;
|
||||
|
||||
@@ -399,11 +399,11 @@ QString SuggestionsController::getEmojiQuery() {
|
||||
}
|
||||
|
||||
auto cursor = _field->textCursor();
|
||||
auto position = _field->textCursor().position();
|
||||
if (cursor.anchor() != position) {
|
||||
if (cursor.hasSelection()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
auto position = cursor.position();
|
||||
auto findTextPart = [this, &position] {
|
||||
auto document = _field->document();
|
||||
auto block = document->findBlock(position);
|
||||
|
||||
@@ -63,23 +63,23 @@ GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent) : InnerFooter(p
|
||||
, _pan(parent)
|
||||
, _field(this, st::gifsSearchField, langFactory(lng_gifs_search))
|
||||
, _cancel(this, st::gifsSearchCancel) {
|
||||
connect(_field, &Ui::InputField::submitted, this, [this](bool ctrlShiftEnter) {
|
||||
connect(_field, &Ui::InputField::submitted, [=] {
|
||||
_pan->sendInlineRequest();
|
||||
});
|
||||
connect(_field, &Ui::InputField::cancelled, this, [this] {
|
||||
connect(_field, &Ui::InputField::cancelled, [=] {
|
||||
if (_field->getLastText().isEmpty()) {
|
||||
emit _pan->cancelled();
|
||||
} else {
|
||||
_field->setText(QString());
|
||||
}
|
||||
});
|
||||
connect(_field, &Ui::InputField::changed, this, [this] {
|
||||
connect(_field, &Ui::InputField::changed, [=] {
|
||||
_cancel->toggle(
|
||||
!_field->getLastText().isEmpty(),
|
||||
anim::type::normal);
|
||||
_pan->searchForGifs(_field->getLastText());
|
||||
});
|
||||
_cancel->setClickedCallback([this] {
|
||||
_cancel->setClickedCallback([=] {
|
||||
_field->setText(QString());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,14 +9,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "history/history_widget.h"
|
||||
#include "base/qthelp_regex.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwindow.h"
|
||||
#include "auth_session.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_history.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using EditLinkAction = Ui::InputField::EditLinkAction;
|
||||
using EditLinkSelection = Ui::InputField::EditLinkSelection;
|
||||
|
||||
constexpr auto kParseLinksTimeout = TimeMs(1000);
|
||||
const auto kMentionTagStart = qstr("mention://user.");
|
||||
|
||||
bool IsMentionLink(const QString &link) {
|
||||
return link.startsWith(kMentionTagStart);
|
||||
}
|
||||
|
||||
// For mention tags save and validate userId, ignore tags for different userId.
|
||||
class FieldTagMimeProcessor : public Ui::InputField::TagMimeProcessor {
|
||||
@@ -26,7 +38,7 @@ public:
|
||||
}
|
||||
|
||||
QString tagFromMimeTag(const QString &mimeTag) override {
|
||||
if (mimeTag.startsWith(qstr("mention://"))) {
|
||||
if (IsMentionLink(mimeTag)) {
|
||||
auto match = QRegularExpression(":(\\d+)$").match(mimeTag);
|
||||
if (!match.hasMatch()
|
||||
|| match.capturedRef(1).toInt() != Auth().userId()) {
|
||||
@@ -39,15 +51,167 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class EditLinkBox : public BoxContent {
|
||||
public:
|
||||
EditLinkBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &link,
|
||||
base::lambda<void(QString, QString)> callback);
|
||||
|
||||
void setInnerFocus() override;
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
QString _startText;
|
||||
QString _startLink;
|
||||
base::lambda<void(QString, QString)> _callback;
|
||||
base::lambda<void()> _setInnerFocus;
|
||||
|
||||
};
|
||||
|
||||
QRegularExpression RegExpProtocol() {
|
||||
static const auto result = QRegularExpression("^([a-zA-Z]+)://");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsGoodProtocol(const QString &protocol) {
|
||||
const auto equals = [&](QLatin1String string) {
|
||||
return protocol.compare(string, Qt::CaseInsensitive) == 0;
|
||||
};
|
||||
return equals(qstr("http"))
|
||||
|| equals(qstr("https"))
|
||||
|| equals(qstr("tg"));
|
||||
}
|
||||
|
||||
QString NormalizeUrl(const QString &value) {
|
||||
const auto trimmed = value.trimmed();
|
||||
if (trimmed.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
const auto match = TextUtilities::RegExpDomainExplicit().match(trimmed);
|
||||
if (!match.hasMatch()) {
|
||||
const auto domain = TextUtilities::RegExpDomain().match(trimmed);
|
||||
if (!domain.hasMatch() || domain.capturedStart() != 0) {
|
||||
return QString();
|
||||
}
|
||||
return qstr("http://") + trimmed;
|
||||
} else if (match.capturedStart() != 0) {
|
||||
return QString();
|
||||
}
|
||||
const auto protocolMatch = RegExpProtocol().match(trimmed);
|
||||
Assert(protocolMatch.hasMatch());
|
||||
return IsGoodProtocol(protocolMatch.captured(1)) ? trimmed : QString();
|
||||
}
|
||||
|
||||
//bool ValidateUrl(const QString &value) {
|
||||
// const auto match = TextUtilities::RegExpDomain().match(value);
|
||||
// if (!match.hasMatch() || match.capturedStart() != 0) {
|
||||
// return false;
|
||||
// }
|
||||
// const auto protocolMatch = RegExpProtocol().match(value);
|
||||
// return protocolMatch.hasMatch()
|
||||
// && IsGoodProtocol(protocolMatch.captured(1));
|
||||
//}
|
||||
|
||||
EditLinkBox::EditLinkBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &link,
|
||||
base::lambda<void(QString, QString)> callback)
|
||||
: _startText(text)
|
||||
, _startLink(link)
|
||||
, _callback(std::move(callback)) {
|
||||
Expects(_callback != nullptr);
|
||||
}
|
||||
|
||||
void EditLinkBox::setInnerFocus() {
|
||||
Expects(_setInnerFocus != nullptr);
|
||||
|
||||
_setInnerFocus();
|
||||
}
|
||||
|
||||
void EditLinkBox::prepare() {
|
||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
|
||||
const auto text = content->add(
|
||||
object_ptr<Ui::InputField>(
|
||||
content,
|
||||
st::defaultInputField,
|
||||
langFactory(lng_formatting_link_text),
|
||||
_startText),
|
||||
st::markdownLinkFieldPadding);
|
||||
text->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
text->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
|
||||
const auto url = content->add(
|
||||
object_ptr<Ui::InputField>(
|
||||
content,
|
||||
st::defaultInputField,
|
||||
langFactory(lng_formatting_link_url),
|
||||
_startLink.trimmed()),
|
||||
st::markdownLinkFieldPadding);
|
||||
|
||||
const auto submit = [=] {
|
||||
const auto linkText = text->getLastText();
|
||||
const auto linkUrl = NormalizeUrl(url->getLastText());
|
||||
if (linkText.isEmpty()) {
|
||||
text->showError();
|
||||
return;
|
||||
} else if (linkUrl.isEmpty()) {
|
||||
url->showError();
|
||||
return;
|
||||
}
|
||||
const auto weak = make_weak(this);
|
||||
_callback(linkText, linkUrl);
|
||||
if (weak) {
|
||||
closeBox();
|
||||
}
|
||||
};
|
||||
|
||||
connect(text, &Ui::InputField::submitted, [=] {
|
||||
url->setFocusFast();
|
||||
});
|
||||
connect(url, &Ui::InputField::submitted, [=] {
|
||||
if (text->getLastText().isEmpty()) {
|
||||
text->setFocusFast();
|
||||
} else {
|
||||
submit();
|
||||
}
|
||||
});
|
||||
|
||||
setTitle(langFactory(lng_formatting_link_create_title));
|
||||
|
||||
addButton(langFactory(lng_formatting_link_create), submit);
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
content->resizeToWidth(st::boxWidth);
|
||||
content->moveToLeft(0, 0);
|
||||
setDimensions(st::boxWidth, content->height());
|
||||
|
||||
_setInnerFocus = [=] {
|
||||
(_startText.isEmpty() ? text : url)->setFocusFast();
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QString ConvertTagToMimeTag(const QString &tagId) {
|
||||
if (tagId.startsWith(qstr("mention://"))) {
|
||||
if (IsMentionLink(tagId)) {
|
||||
return tagId + ':' + QString::number(Auth().userId());
|
||||
}
|
||||
return tagId;
|
||||
}
|
||||
|
||||
QString PrepareMentionTag(not_null<UserData*> user) {
|
||||
return kMentionTagStart
|
||||
+ QString::number(user->bareId())
|
||||
+ '.'
|
||||
+ QString::number(user->accessHash());
|
||||
}
|
||||
|
||||
EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
|
||||
EntitiesInText result;
|
||||
if (tags.isEmpty()) {
|
||||
@@ -55,7 +219,6 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
|
||||
}
|
||||
|
||||
result.reserve(tags.size());
|
||||
auto mentionStart = qstr("mention://user.");
|
||||
for (const auto &tag : tags) {
|
||||
const auto push = [&](
|
||||
EntityInTextType type,
|
||||
@@ -63,8 +226,8 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
|
||||
result.push_back(
|
||||
EntityInText(type, tag.offset, tag.length, data));
|
||||
};
|
||||
if (tag.id.startsWith(mentionStart)) {
|
||||
if (auto match = qthelp::regex_match("^(\\d+\\.\\d+)(/|$)", tag.id.midRef(mentionStart.size()))) {
|
||||
if (IsMentionLink(tag.id)) {
|
||||
if (auto match = qthelp::regex_match("^(\\d+\\.\\d+)(/|$)", tag.id.midRef(kMentionTagStart.size()))) {
|
||||
push(EntityInTextMentionName, match->captured(1));
|
||||
}
|
||||
} else if (tag.id == Ui::InputField::kTagBold) {
|
||||
@@ -75,6 +238,8 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
|
||||
push(EntityInTextCode);
|
||||
} else if (tag.id == Ui::InputField::kTagPre) {
|
||||
push(EntityInTextPre);
|
||||
} else /*if (ValidateUrl(tag.id)) */{ // We validate when we insert.
|
||||
push(EntityInTextCustomUrl, tag.id);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -95,7 +260,14 @@ TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities) {
|
||||
case EntityInTextMentionName: {
|
||||
auto match = QRegularExpression("^(\\d+\\.\\d+)$").match(entity.data());
|
||||
if (match.hasMatch()) {
|
||||
push(qstr("mention://user.") + entity.data());
|
||||
push(kMentionTagStart + entity.data());
|
||||
}
|
||||
} break;
|
||||
case EntityInTextCustomUrl: {
|
||||
const auto url = entity.data();
|
||||
if (Ui::InputField::IsValidMarkdownLink(url)
|
||||
&& !IsMentionLink(url)) {
|
||||
push(url);
|
||||
}
|
||||
} break;
|
||||
case EntityInTextBold: push(Ui::InputField::kTagBold); break;
|
||||
@@ -135,7 +307,38 @@ void SetClipboardWithEntities(
|
||||
}
|
||||
}
|
||||
|
||||
void InitMessageField(not_null<Ui::InputField*> field) {
|
||||
base::lambda<bool(
|
||||
Ui::InputField::EditLinkSelection selection,
|
||||
QString text,
|
||||
QString link,
|
||||
EditLinkAction action)> DefaultEditLinkCallback(
|
||||
not_null<Window::Controller*> controller,
|
||||
not_null<Ui::InputField*> field) {
|
||||
const auto weak = make_weak(field);
|
||||
return [=](
|
||||
EditLinkSelection selection,
|
||||
QString text,
|
||||
QString link,
|
||||
EditLinkAction action) {
|
||||
if (action == EditLinkAction::Check) {
|
||||
return Ui::InputField::IsValidMarkdownLink(link)
|
||||
&& !IsMentionLink(link);
|
||||
}
|
||||
Ui::show(Box<EditLinkBox>(text, link, [=](
|
||||
const QString &text,
|
||||
const QString &link) {
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->commitMarkdownLinkEdit(selection, text, link);
|
||||
}
|
||||
}), LayerOption::KeepOther);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void InitMessageField(
|
||||
not_null<Window::Controller*> controller,
|
||||
not_null<Ui::InputField*> field) {
|
||||
field->setMinHeight(st::historySendSize.height() - 2 * st::historySendPadding);
|
||||
field->setMaxHeight(st::historyComposeFieldMaxHeight);
|
||||
|
||||
@@ -147,7 +350,9 @@ void InitMessageField(not_null<Ui::InputField*> field) {
|
||||
field->customTab(true);
|
||||
field->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
field->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
field->setMarkdownReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
field->setMarkdownReplacesEnabled(rpl::single(true));
|
||||
field->setEditLinkCallback(
|
||||
DefaultEditLinkCallback(controller, field));
|
||||
}
|
||||
|
||||
bool HasSendText(not_null<const Ui::InputField*> field) {
|
||||
@@ -237,11 +442,11 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery(
|
||||
auto result = AutocompleteQuery();
|
||||
|
||||
const auto cursor = field->textCursor();
|
||||
const auto position = cursor.position();
|
||||
if (cursor.anchor() != position) {
|
||||
if (cursor.hasSelection()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto position = cursor.position();
|
||||
const auto document = field->document();
|
||||
const auto block = document->findBlock(position);
|
||||
for (auto item = block.begin(); !item.atEnd(); ++item) {
|
||||
@@ -363,13 +568,62 @@ const rpl::variable<QStringList> &MessageLinksParser::list() const {
|
||||
}
|
||||
|
||||
void MessageLinksParser::parse() {
|
||||
const auto &text = _field->getTextWithTags().text;
|
||||
const auto &textWithTags = _field->getTextWithTags();
|
||||
const auto &text = textWithTags.text;
|
||||
const auto &tags = textWithTags.tags;
|
||||
const auto &markdownTags = _field->getMarkdownTags();
|
||||
if (text.isEmpty()) {
|
||||
_list = QStringList();
|
||||
return;
|
||||
}
|
||||
|
||||
auto ranges = QVector<LinkRange>();
|
||||
|
||||
auto tag = tags.begin();
|
||||
const auto tagsEnd = tags.end();
|
||||
const auto processTag = [&] {
|
||||
Expects(tag != tagsEnd);
|
||||
|
||||
if (Ui::InputField::IsValidMarkdownLink(tag->id)
|
||||
&& !IsMentionLink(tag->id)) {
|
||||
ranges.push_back({ tag->offset, tag->length, tag->id });
|
||||
}
|
||||
++tag;
|
||||
};
|
||||
const auto processTagsBefore = [&](int offset) {
|
||||
while (tag != tagsEnd && tag->offset + tag->length <= offset) {
|
||||
processTag();
|
||||
}
|
||||
};
|
||||
const auto hasTagsIntersection = [&](int till) {
|
||||
if (tag == tagsEnd || tag->offset >= till) {
|
||||
return false;
|
||||
}
|
||||
while (tag != tagsEnd && tag->offset < till) {
|
||||
processTag();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto markdownTag = markdownTags.begin();
|
||||
const auto markdownTagsEnd = markdownTags.end();
|
||||
const auto markdownTagsAllow = [&](int from, int length) {
|
||||
while (markdownTag != markdownTagsEnd
|
||||
&& (markdownTag->start + markdownTag->length <= from
|
||||
|| !markdownTag->closed)) {
|
||||
++markdownTag;
|
||||
continue;
|
||||
}
|
||||
if (markdownTag == markdownTagsEnd
|
||||
|| markdownTag->start >= from + length) {
|
||||
return true;
|
||||
}
|
||||
// Ignore http-links that are completely inside some tags.
|
||||
// This will allow sending http://test.com/__test__/test correctly.
|
||||
return (markdownTag->start > from
|
||||
|| markdownTag->start + markdownTag->length < from + length);
|
||||
};
|
||||
|
||||
const auto len = text.size();
|
||||
const QChar *start = text.unicode(), *end = start + text.size();
|
||||
for (auto offset = 0, matchOffset = offset; offset < len;) {
|
||||
@@ -429,9 +683,20 @@ void MessageLinksParser::parse() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ranges.push_back({ domainOffset, static_cast<int>(p - start - domainOffset) });
|
||||
const auto range = LinkRange {
|
||||
domainOffset,
|
||||
static_cast<int>(p - start - domainOffset),
|
||||
QString()
|
||||
};
|
||||
processTagsBefore(domainOffset);
|
||||
if (!hasTagsIntersection(range.start + range.length)) {
|
||||
if (markdownTagsAllow(range.start, range.length)) {
|
||||
ranges.push_back(range);
|
||||
}
|
||||
}
|
||||
offset = matchOffset = p - start;
|
||||
}
|
||||
processTagsBefore(QFIXED_MAX);
|
||||
|
||||
apply(text, ranges);
|
||||
}
|
||||
@@ -441,13 +706,17 @@ void MessageLinksParser::apply(
|
||||
const QVector<LinkRange> &ranges) {
|
||||
const auto count = int(ranges.size());
|
||||
const auto current = _list.current();
|
||||
const auto computeLink = [&](const LinkRange &range) {
|
||||
return range.custom.isEmpty()
|
||||
? text.midRef(range.start, range.length)
|
||||
: range.custom.midRef(0);
|
||||
};
|
||||
const auto changed = [&] {
|
||||
if (current.size() != count) {
|
||||
return true;
|
||||
}
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
const auto &range = ranges[i];
|
||||
if (text.midRef(range.start, range.length) != current[i]) {
|
||||
if (computeLink(ranges[i]) != current[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -459,7 +728,7 @@ void MessageLinksParser::apply(
|
||||
auto parsed = QStringList();
|
||||
parsed.reserve(count);
|
||||
for (const auto &range : ranges) {
|
||||
parsed.push_back(text.mid(range.start, range.length));
|
||||
parsed.push_back(computeLink(range).toString());
|
||||
}
|
||||
_list = std::move(parsed);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ class Controller;
|
||||
} // namespace Window
|
||||
|
||||
QString ConvertTagToMimeTag(const QString &tagId);
|
||||
QString PrepareMentionTag(not_null<UserData*> user);
|
||||
|
||||
EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags);
|
||||
TextWithTags::Tags ConvertEntitiesToTextTags(
|
||||
@@ -26,7 +27,16 @@ void SetClipboardWithEntities(
|
||||
const TextWithEntities &forClipboard,
|
||||
QClipboard::Mode mode = QClipboard::Clipboard);
|
||||
|
||||
void InitMessageField(not_null<Ui::InputField*> field);
|
||||
base::lambda<bool(
|
||||
Ui::InputField::EditLinkSelection selection,
|
||||
QString text,
|
||||
QString link,
|
||||
Ui::InputField::EditLinkAction action)> DefaultEditLinkCallback(
|
||||
not_null<Window::Controller*> controller,
|
||||
not_null<Ui::InputField*> field);
|
||||
void InitMessageField(
|
||||
not_null<Window::Controller*> controller,
|
||||
not_null<Ui::InputField*> field);
|
||||
bool HasSendText(not_null<const Ui::InputField*> field);
|
||||
|
||||
struct InlineBotQuery {
|
||||
@@ -71,9 +81,12 @@ private:
|
||||
struct LinkRange {
|
||||
int start;
|
||||
int length;
|
||||
QString custom;
|
||||
};
|
||||
friend inline bool operator==(const LinkRange &a, const LinkRange &b) {
|
||||
return (a.start == b.start) && (a.length == b.length);
|
||||
return (a.start == b.start)
|
||||
&& (a.length == b.length)
|
||||
&& (a.custom == b.custom);
|
||||
}
|
||||
friend inline bool operator!=(const LinkRange &a, const LinkRange &b) {
|
||||
return !(a == b);
|
||||
|
||||
@@ -195,11 +195,11 @@ void StickersListWidget::Footer::initSearch() {
|
||||
_searchField->setText(QString());
|
||||
}
|
||||
};
|
||||
connect(_searchField, &Ui::InputField::submitted, this, [this](bool ctrlShiftEnter) {
|
||||
connect(_searchField, &Ui::InputField::submitted, [=] {
|
||||
_pan->sendSearchRequest();
|
||||
});
|
||||
connect(_searchField, &Ui::InputField::cancelled, this, cancelSearch);
|
||||
connect(_searchField, &Ui::InputField::changed, this, [this] {
|
||||
connect(_searchField, &Ui::InputField::cancelled, cancelSearch);
|
||||
connect(_searchField, &Ui::InputField::changed, [=] {
|
||||
_pan->searchForSets(_searchField->getLastText());
|
||||
});
|
||||
_searchCancel->setClickedCallback(cancelSearch);
|
||||
|
||||
@@ -55,8 +55,8 @@ addChildParentFlags('MTPDchannelForbidden', 'MTPDchannel');
|
||||
parentFlagsCheck = {};
|
||||
|
||||
countedTypeIdExceptions = {};
|
||||
countedTypeIdExceptions[77] = countedTypeIdExceptions[78] = {}
|
||||
countedTypeIdExceptions[77]['channel'] = countedTypeIdExceptions[78]['channel'] = True
|
||||
countedTypeIdExceptions[77] = countedTypeIdExceptions[78] = countedTypeIdExceptions[79] = {}
|
||||
countedTypeIdExceptions[77]['channel'] = countedTypeIdExceptions[78]['channel'] = countedTypeIdExceptions[79]['channel'] = True
|
||||
countedTypeIdExceptions['ipPortSecret'] = True
|
||||
countedTypeIdExceptions['accessPointRule'] = True
|
||||
countedTypeIdExceptions['help_configSimple'] = True
|
||||
|
||||
@@ -275,8 +275,6 @@ enum {
|
||||
WaitForChannelGetDifference = 1000, // 1s wait after show channel history before sending getChannelDifference
|
||||
|
||||
MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory
|
||||
NotifySettingSaveTimeout = 1000, // wait 1 second before saving notify setting to server
|
||||
UpdateChunk = 100 * 1024, // 100kb parts when downloading the update
|
||||
IdleMsecs = 60 * 1000, // after 60secs without user input we think we are idle
|
||||
|
||||
SendViewsTimeout = 1000, // send views each second
|
||||
|
||||
@@ -87,6 +87,30 @@ std::map<int, const char*> AlphaLogs() {
|
||||
"after typing (instead of after sending) and can be "
|
||||
"rolled back using Backspace or Ctrl/Cmd + Z. "
|
||||
"Replacement no longer happens when pasting text."
|
||||
},
|
||||
{
|
||||
1002023,
|
||||
"\xE2\x80\x94 Apply formatting from input field context menu.\n"
|
||||
|
||||
"\xE2\x80\x94 Apply formatting by hotkeys.\n"
|
||||
|
||||
"\xE2\x80\x94 Bug fixes and other minor improvements."
|
||||
},
|
||||
{
|
||||
1002024,
|
||||
"\xE2\x80\x94 Add links with custom text from context menu "
|
||||
"or by Ctrl/Cmd + K keyboard shortcut."
|
||||
},
|
||||
{
|
||||
1002025,
|
||||
"\xE2\x80\x94 Apply markdown formatting (```, `, **, __) "
|
||||
"only when sending the message.\n"
|
||||
|
||||
"\xE2\x80\x94 Display connection quality bars in calls.\n"
|
||||
|
||||
"\xE2\x80\x94 Telegram Desktop can update itself through MTProto.\n"
|
||||
|
||||
"\xE2\x80\x94 Bug fixes and other minor improvements."
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace MTP {
|
||||
class Instance;
|
||||
} // namespace MTP
|
||||
|
||||
namespace Core {
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
@@ -37,6 +41,8 @@ public:
|
||||
void stop();
|
||||
void test();
|
||||
|
||||
void setMtproto(const QPointer<MTP::Instance> &mtproto);
|
||||
|
||||
State state() const;
|
||||
int already() const;
|
||||
int size() const;
|
||||
|
||||
@@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#define BETA_VERSION_MACRO (0ULL)
|
||||
|
||||
constexpr int AppVersion = 1002022;
|
||||
constexpr str_const AppVersionStr = "1.2.22";
|
||||
constexpr bool AppAlphaVersion = true;
|
||||
constexpr int AppVersion = 1003000;
|
||||
constexpr str_const AppVersionStr = "1.3";
|
||||
constexpr bool AppAlphaVersion = false;
|
||||
constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO;
|
||||
|
||||
@@ -12,11 +12,12 @@ namespace {
|
||||
|
||||
MTPinputPeerNotifySettings DefaultSettings() {
|
||||
const auto flags = MTPDpeerNotifySettings::Flag::f_show_previews;
|
||||
const auto muteValue = TimeId(0);
|
||||
return MTP_inputPeerNotifySettings(
|
||||
MTP_flags(mtpCastFlags(flags)),
|
||||
MTP_int(muteValue),
|
||||
MTP_string("default"));
|
||||
MTP_flags(0),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPint(),
|
||||
MTPstring());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -25,98 +26,121 @@ class NotifySettingsValue {
|
||||
public:
|
||||
NotifySettingsValue(const MTPDpeerNotifySettings &data);
|
||||
|
||||
using MuteChange = NotifySettings::MuteChange;
|
||||
using SilentPostsChange = NotifySettings::SilentPostsChange;
|
||||
|
||||
bool change(const MTPDpeerNotifySettings &data);
|
||||
bool change(
|
||||
MuteChange mute,
|
||||
SilentPostsChange silent,
|
||||
int muteForSeconds);
|
||||
TimeMs muteFinishesIn() const;
|
||||
bool silentPosts() const;
|
||||
base::optional<int> muteForSeconds,
|
||||
base::optional<bool> silentPosts);
|
||||
|
||||
base::optional<TimeId> muteUntil() const;
|
||||
base::optional<bool> silentPosts() const;
|
||||
MTPinputPeerNotifySettings serialize() const;
|
||||
|
||||
private:
|
||||
bool change(
|
||||
MTPDpeerNotifySettings::Flags flags,
|
||||
TimeId mute,
|
||||
QString sound);
|
||||
base::optional<int> mute,
|
||||
base::optional<QString> sound,
|
||||
base::optional<bool> showPreviews,
|
||||
base::optional<bool> silentPosts);
|
||||
|
||||
MTPDpeerNotifySettings::Flags _flags;
|
||||
TimeId _mute;
|
||||
QString _sound;
|
||||
base::optional<TimeId> _mute;
|
||||
base::optional<QString> _sound;
|
||||
base::optional<bool> _silent;
|
||||
base::optional<bool> _showPreviews;
|
||||
|
||||
};
|
||||
|
||||
NotifySettingsValue::NotifySettingsValue(const MTPDpeerNotifySettings &data)
|
||||
: _flags(data.vflags.v)
|
||||
, _mute(data.vmute_until.v)
|
||||
, _sound(qs(data.vsound)) {
|
||||
}
|
||||
|
||||
bool NotifySettingsValue::silentPosts() const {
|
||||
return _flags & MTPDpeerNotifySettings::Flag::f_silent;
|
||||
NotifySettingsValue::NotifySettingsValue(
|
||||
const MTPDpeerNotifySettings &data) {
|
||||
change(data);
|
||||
}
|
||||
|
||||
bool NotifySettingsValue::change(const MTPDpeerNotifySettings &data) {
|
||||
return change(data.vflags.v, data.vmute_until.v, qs(data.vsound));
|
||||
return change(data.has_mute_until()
|
||||
? base::make_optional(data.vmute_until.v)
|
||||
: base::none, data.has_sound()
|
||||
? base::make_optional(qs(data.vsound))
|
||||
: base::none, data.has_show_previews()
|
||||
? base::make_optional(mtpIsTrue(data.vshow_previews))
|
||||
: base::none, data.has_silent()
|
||||
? base::make_optional(mtpIsTrue(data.vsilent))
|
||||
: base::none);
|
||||
}
|
||||
|
||||
bool NotifySettingsValue::change(
|
||||
MuteChange mute,
|
||||
SilentPostsChange silent,
|
||||
int muteForSeconds) {
|
||||
const auto newFlags = [&] {
|
||||
auto result = _flags;
|
||||
if (silent == SilentPostsChange::Silent) {
|
||||
result |= MTPDpeerNotifySettings::Flag::f_silent;
|
||||
} else if (silent == SilentPostsChange::Notify) {
|
||||
result &= ~MTPDpeerNotifySettings::Flag::f_silent;
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
const auto newMute = (mute == MuteChange::Mute)
|
||||
? (unixtime() + muteForSeconds)
|
||||
: (mute == MuteChange::Ignore) ? _mute : 0;
|
||||
const auto newSound = (newMute == 0 && _sound.isEmpty())
|
||||
base::optional<int> muteForSeconds,
|
||||
base::optional<bool> silentPosts) {
|
||||
const auto now = unixtime();
|
||||
const auto notMuted = muteForSeconds
|
||||
? !(*muteForSeconds)
|
||||
: (!_mute || *_mute <= now);
|
||||
return change(muteForSeconds
|
||||
? base::make_optional((*muteForSeconds > 0)
|
||||
? (now + *muteForSeconds)
|
||||
: 0)
|
||||
: base::none, (_sound && _sound->isEmpty() && notMuted)
|
||||
? qsl("default")
|
||||
: _sound;
|
||||
return change(newFlags, newMute, newSound);
|
||||
: _sound, _showPreviews, silentPosts
|
||||
? base::make_optional(*silentPosts)
|
||||
: base::none);
|
||||
}
|
||||
|
||||
bool NotifySettingsValue::change(
|
||||
MTPDpeerNotifySettings::Flags flags,
|
||||
TimeId mute,
|
||||
QString sound) {
|
||||
if (_flags == flags && _mute == mute && _sound == sound) {
|
||||
base::optional<int> mute,
|
||||
base::optional<QString> sound,
|
||||
base::optional<bool> showPreviews,
|
||||
base::optional<bool> silentPosts) {
|
||||
if (_mute == mute
|
||||
&& _sound == sound
|
||||
&& _showPreviews == showPreviews
|
||||
&& _silent == silentPosts) {
|
||||
return false;
|
||||
}
|
||||
_flags = flags;
|
||||
_mute = mute;
|
||||
_sound = sound;
|
||||
_showPreviews = showPreviews;
|
||||
_silent = silentPosts;
|
||||
return true;
|
||||
}
|
||||
|
||||
TimeMs NotifySettingsValue::muteFinishesIn() const {
|
||||
auto now = unixtime();
|
||||
if (_mute > now) {
|
||||
return (_mute - now + 1) * 1000LL;
|
||||
}
|
||||
return 0;
|
||||
base::optional<TimeId> NotifySettingsValue::muteUntil() const {
|
||||
return _mute;
|
||||
}
|
||||
|
||||
base::optional<bool> NotifySettingsValue::silentPosts() const {
|
||||
return _silent;
|
||||
}
|
||||
|
||||
MTPinputPeerNotifySettings NotifySettingsValue::serialize() const {
|
||||
using Flag = MTPDinputPeerNotifySettings::Flag;
|
||||
const auto flag = [](auto &&optional, Flag flag) {
|
||||
return optional.has_value() ? flag : Flag(0);
|
||||
};
|
||||
return MTP_inputPeerNotifySettings(
|
||||
MTP_flags(mtpCastFlags(_flags)),
|
||||
MTP_int(_mute),
|
||||
MTP_string(_sound));
|
||||
MTP_flags(flag(_mute, Flag::f_mute_until)
|
||||
| flag(_sound, Flag::f_sound)
|
||||
| flag(_silent, Flag::f_silent)
|
||||
| flag(_showPreviews, Flag::f_show_previews)),
|
||||
MTP_bool(_showPreviews ? *_showPreviews : true),
|
||||
MTP_bool(_silent ? *_silent : false),
|
||||
MTP_int(_mute ? *_mute : false),
|
||||
MTP_string(_sound ? *_sound : QString()));
|
||||
}
|
||||
|
||||
NotifySettings::NotifySettings() = default;
|
||||
|
||||
bool NotifySettings::change(const MTPPeerNotifySettings &settings) {
|
||||
Expects(settings.type() == mtpc_peerNotifySettings);
|
||||
|
||||
auto &data = settings.c_peerNotifySettings();
|
||||
const auto empty = !data.vflags.v;
|
||||
if (empty) {
|
||||
if (!_known || _value) {
|
||||
_known = true;
|
||||
_value = nullptr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (_value) {
|
||||
return _value->change(data);
|
||||
}
|
||||
@@ -125,47 +149,42 @@ bool NotifySettings::change(const MTPPeerNotifySettings &settings) {
|
||||
return true;
|
||||
}
|
||||
|
||||
NotifySettings::NotifySettings() = default;
|
||||
|
||||
bool NotifySettings::change(
|
||||
MuteChange mute,
|
||||
SilentPostsChange silent,
|
||||
int muteForSeconds) {
|
||||
Expects(mute != MuteChange::Mute || muteForSeconds > 0);
|
||||
|
||||
if (mute == MuteChange::Ignore && silent == SilentPostsChange::Ignore) {
|
||||
base::optional<int> muteForSeconds,
|
||||
base::optional<bool> silentPosts) {
|
||||
if (!muteForSeconds && !silentPosts) {
|
||||
return false;
|
||||
} else if (_value) {
|
||||
return _value->change(muteForSeconds, silentPosts);
|
||||
}
|
||||
if (_value) {
|
||||
return _value->change(mute, silent, muteForSeconds);
|
||||
}
|
||||
const auto flags = MTPDpeerNotifySettings::Flag::f_show_previews
|
||||
| ((silent == SilentPostsChange::Silent)
|
||||
? MTPDpeerNotifySettings::Flag::f_silent
|
||||
: MTPDpeerNotifySettings::Flag(0));
|
||||
const auto muteUntil = (mute == MuteChange::Mute)
|
||||
? (unixtime() + muteForSeconds)
|
||||
using Flag = MTPDpeerNotifySettings::Flag;
|
||||
const auto flags = (muteForSeconds ? Flag::f_mute_until : Flag(0))
|
||||
| (silentPosts ? Flag::f_silent : Flag(0));
|
||||
const auto muteUntil = muteForSeconds
|
||||
? (unixtime() + *muteForSeconds)
|
||||
: 0;
|
||||
return change(MTP_peerNotifySettings(
|
||||
MTP_flags(flags),
|
||||
MTP_int(muteUntil),
|
||||
MTP_string("default")));
|
||||
MTPBool(),
|
||||
silentPosts ? MTP_bool(*silentPosts) : MTPBool(),
|
||||
muteForSeconds ? MTP_int(unixtime() + *muteForSeconds) : MTPint(),
|
||||
MTPstring()));
|
||||
}
|
||||
|
||||
TimeMs NotifySettings::muteFinishesIn() const {
|
||||
base::optional<TimeId> NotifySettings::muteUntil() const {
|
||||
return _value
|
||||
? _value->muteFinishesIn()
|
||||
: 0LL;
|
||||
? _value->muteUntil()
|
||||
: base::none;
|
||||
}
|
||||
|
||||
bool NotifySettings::settingsUnknown() const {
|
||||
return !_known;
|
||||
}
|
||||
|
||||
bool NotifySettings::silentPosts() const {
|
||||
base::optional<bool> NotifySettings::silentPosts() const {
|
||||
return _value
|
||||
? _value->silentPosts()
|
||||
: false;
|
||||
: base::none;
|
||||
}
|
||||
|
||||
MTPinputPeerNotifySettings NotifySettings::serialize() const {
|
||||
|
||||
@@ -15,25 +15,16 @@ class NotifySettings {
|
||||
public:
|
||||
NotifySettings();
|
||||
|
||||
enum class MuteChange {
|
||||
Ignore,
|
||||
Mute,
|
||||
Unmute,
|
||||
};
|
||||
enum class SilentPostsChange {
|
||||
Ignore,
|
||||
Silent,
|
||||
Notify,
|
||||
};
|
||||
static constexpr auto kDefaultMutePeriod = 86400 * 365;
|
||||
|
||||
bool change(const MTPPeerNotifySettings &settings);
|
||||
bool change(
|
||||
MuteChange mute,
|
||||
SilentPostsChange silent,
|
||||
int muteForSeconds);
|
||||
TimeMs muteFinishesIn() const;
|
||||
base::optional<int> muteForSeconds,
|
||||
base::optional<bool> silentPosts);
|
||||
|
||||
bool settingsUnknown() const;
|
||||
bool silentPosts() const;
|
||||
base::optional<TimeId> muteUntil() const;
|
||||
base::optional<bool> silentPosts() const;
|
||||
MTPinputPeerNotifySettings serialize() const;
|
||||
|
||||
~NotifySettings();
|
||||
|
||||
@@ -68,30 +68,26 @@ public:
|
||||
bool isVerified() const;
|
||||
bool isMegagroup() const;
|
||||
|
||||
TimeMs notifyMuteFinishesIn() const {
|
||||
return _notify.muteFinishesIn();
|
||||
base::optional<TimeId> notifyMuteUntil() const {
|
||||
return _notify.muteUntil();
|
||||
}
|
||||
bool notifyChange(const MTPPeerNotifySettings &settings) {
|
||||
return _notify.change(settings);
|
||||
}
|
||||
bool notifyChange(
|
||||
Data::NotifySettings::MuteChange mute,
|
||||
Data::NotifySettings::SilentPostsChange silent,
|
||||
int muteForSeconds) {
|
||||
return _notify.change(mute, silent, muteForSeconds);
|
||||
base::optional<int> muteForSeconds,
|
||||
base::optional<bool> silentPosts) {
|
||||
return _notify.change(muteForSeconds, silentPosts);
|
||||
}
|
||||
bool notifySettingsUnknown() const {
|
||||
return _notify.settingsUnknown();
|
||||
}
|
||||
bool notifySilentPosts() const {
|
||||
base::optional<bool> notifySilentPosts() const {
|
||||
return _notify.silentPosts();
|
||||
}
|
||||
MTPinputPeerNotifySettings notifySerialize() const {
|
||||
return _notify.serialize();
|
||||
}
|
||||
bool isMuted() const {
|
||||
return (notifyMuteFinishesIn() > 0);
|
||||
}
|
||||
|
||||
bool canWrite() const;
|
||||
UserData *asUser();
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/history_media.h"
|
||||
@@ -26,6 +27,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxNotifyCheckDelay = 24 * 3600 * TimeMs(1000);
|
||||
|
||||
using ViewElement = HistoryView::Element;
|
||||
|
||||
// s: box 100x100
|
||||
@@ -59,7 +62,8 @@ void UpdateImage(ImagePtr &old, ImagePtr now) {
|
||||
|
||||
Session::Session(not_null<AuthSession*> session)
|
||||
: _session(session)
|
||||
, _groups(this) {
|
||||
, _groups(this)
|
||||
, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) {
|
||||
setupContactViewsViewer();
|
||||
setupChannelLeavingViewer();
|
||||
}
|
||||
@@ -545,6 +549,77 @@ void Session::setIsPinned(const Dialogs::Key &key, bool pinned) {
|
||||
}
|
||||
}
|
||||
|
||||
NotifySettings &Session::defaultNotifySettings(
|
||||
not_null<const PeerData*> peer) {
|
||||
return peer->isUser()
|
||||
? _defaultUserNotifySettings
|
||||
: _defaultChatNotifySettings;
|
||||
}
|
||||
|
||||
const NotifySettings &Session::defaultNotifySettings(
|
||||
not_null<const PeerData*> peer) const {
|
||||
return peer->isUser()
|
||||
? _defaultUserNotifySettings
|
||||
: _defaultChatNotifySettings;
|
||||
}
|
||||
|
||||
void Session::updateNotifySettingsLocal(not_null<PeerData*> peer) {
|
||||
const auto history = App::historyLoaded(peer->id);
|
||||
auto changesIn = TimeMs(0);
|
||||
const auto muted = notifyIsMuted(peer, &changesIn);
|
||||
if (history && history->changeMute(muted)) {
|
||||
// Notification already sent.
|
||||
} else {
|
||||
Notify::peerUpdatedDelayed(
|
||||
peer,
|
||||
Notify::PeerUpdate::Flag::NotificationsEnabled);
|
||||
}
|
||||
|
||||
if (muted) {
|
||||
_mutedPeers.emplace(peer);
|
||||
unmuteByFinishedDelayed(changesIn);
|
||||
if (history) {
|
||||
_session->notifications().clearFromHistory(history);
|
||||
}
|
||||
} else {
|
||||
_mutedPeers.erase(peer);
|
||||
}
|
||||
}
|
||||
|
||||
void Session::unmuteByFinishedDelayed(TimeMs delay) {
|
||||
accumulate_max(delay, kMaxNotifyCheckDelay);
|
||||
if (!_unmuteByFinishedTimer.isActive()
|
||||
|| _unmuteByFinishedTimer.remainingTime() > delay) {
|
||||
_unmuteByFinishedTimer.callOnce(delay);
|
||||
}
|
||||
}
|
||||
|
||||
void Session::unmuteByFinished() {
|
||||
auto changesInMin = TimeMs(0);
|
||||
for (auto i = begin(_mutedPeers); i != end(_mutedPeers);) {
|
||||
const auto history = App::historyLoaded((*i)->id);
|
||||
auto changesIn = TimeMs(0);
|
||||
const auto muted = notifyIsMuted(*i, &changesIn);
|
||||
if (muted) {
|
||||
if (history) {
|
||||
history->changeMute(true);
|
||||
}
|
||||
if (!changesInMin || changesInMin > changesIn) {
|
||||
changesInMin = changesIn;
|
||||
}
|
||||
++i;
|
||||
} else {
|
||||
if (history) {
|
||||
history->changeMute(false);
|
||||
}
|
||||
i = _mutedPeers.erase(i);
|
||||
}
|
||||
}
|
||||
if (changesInMin) {
|
||||
unmuteByFinishedDelayed(changesInMin);
|
||||
}
|
||||
}
|
||||
|
||||
not_null<PhotoData*> Session::photo(PhotoId id) {
|
||||
auto i = _photos.find(id);
|
||||
if (i == _photos.end()) {
|
||||
@@ -1579,6 +1654,148 @@ rpl::producer<FeedId> Session::defaultFeedIdValue() const {
|
||||
return _defaultFeedId.value();
|
||||
}
|
||||
|
||||
void Session::requestNotifySettings(not_null<PeerData*> peer) {
|
||||
if (peer->notifySettingsUnknown()) {
|
||||
_session->api().requestNotifySettings(
|
||||
MTP_inputNotifyPeer(peer->input));
|
||||
}
|
||||
if (defaultNotifySettings(peer).settingsUnknown()) {
|
||||
_session->api().requestNotifySettings(peer->isUser()
|
||||
? MTP_inputNotifyUsers()
|
||||
: MTP_inputNotifyChats());
|
||||
}
|
||||
}
|
||||
|
||||
void Session::applyNotifySetting(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
switch (notifyPeer.type()) {
|
||||
case mtpc_notifyUsers: {
|
||||
if (_defaultUserNotifySettings.change(settings)) {
|
||||
_defaultUserNotifyUpdates.fire({});
|
||||
|
||||
App::enumerateUsers([&](not_null<UserData*> user) {
|
||||
if (!user->notifySettingsUnknown()
|
||||
&& ((!user->notifyMuteUntil()
|
||||
&& _defaultUserNotifySettings.muteUntil())
|
||||
|| (!user->notifySilentPosts()
|
||||
&& _defaultUserNotifySettings.silentPosts()))) {
|
||||
updateNotifySettingsLocal(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
} break;
|
||||
case mtpc_notifyChats: {
|
||||
if (_defaultChatNotifySettings.change(settings)) {
|
||||
_defaultChatNotifyUpdates.fire({});
|
||||
|
||||
App::enumerateChatsChannels([&](not_null<PeerData*> peer) {
|
||||
if (!peer->notifySettingsUnknown()
|
||||
&& ((!peer->notifyMuteUntil()
|
||||
&& _defaultUserNotifySettings.muteUntil())
|
||||
|| (!peer->notifySilentPosts()
|
||||
&& _defaultUserNotifySettings.silentPosts()))) {
|
||||
if (!peer->notifyMuteUntil()) {
|
||||
int a = 0;
|
||||
}
|
||||
updateNotifySettingsLocal(peer);
|
||||
}
|
||||
});
|
||||
}
|
||||
} break;
|
||||
case mtpc_notifyPeer: {
|
||||
const auto &data = notifyPeer.c_notifyPeer();
|
||||
if (const auto peer = App::peerLoaded(peerFromMTP(data.vpeer))) {
|
||||
if (peer->notifyChange(settings)) {
|
||||
updateNotifySettingsLocal(peer);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void Session::updateNotifySettings(
|
||||
not_null<PeerData*> peer,
|
||||
base::optional<int> muteForSeconds,
|
||||
base::optional<bool> silentPosts) {
|
||||
if (peer->notifyChange(muteForSeconds, silentPosts)) {
|
||||
updateNotifySettingsLocal(peer);
|
||||
_session->api().updateNotifySettingsDelayed(peer);
|
||||
}
|
||||
}
|
||||
|
||||
bool Session::notifyIsMuted(
|
||||
not_null<const PeerData*> peer,
|
||||
TimeMs *changesIn) const {
|
||||
const auto resultFromUntil = [&](TimeId until) {
|
||||
const auto now = unixtime();
|
||||
const auto result = (until > now) ? (until - now) : 0;
|
||||
if (changesIn) {
|
||||
*changesIn = (result > 0)
|
||||
? std::min(result * TimeMs(1000), kMaxNotifyCheckDelay)
|
||||
: kMaxNotifyCheckDelay;
|
||||
}
|
||||
return (result > 0);
|
||||
};
|
||||
if (const auto until = peer->notifyMuteUntil()) {
|
||||
return resultFromUntil(*until);
|
||||
}
|
||||
const auto &settings = defaultNotifySettings(peer);
|
||||
if (const auto until = settings.muteUntil()) {
|
||||
return resultFromUntil(*until);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Session::notifySilentPosts(not_null<const PeerData*> peer) const {
|
||||
if (const auto silent = peer->notifySilentPosts()) {
|
||||
return *silent;
|
||||
}
|
||||
const auto &settings = defaultNotifySettings(peer);
|
||||
if (const auto silent = settings.silentPosts()) {
|
||||
return *silent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Session::notifyMuteUnknown(not_null<const PeerData*> peer) const {
|
||||
if (peer->notifySettingsUnknown()) {
|
||||
return true;
|
||||
} else if (const auto nonDefault = peer->notifyMuteUntil()) {
|
||||
return false;
|
||||
}
|
||||
return defaultNotifySettings(peer).settingsUnknown();
|
||||
}
|
||||
|
||||
bool Session::notifySilentPostsUnknown(
|
||||
not_null<const PeerData*> peer) const {
|
||||
if (peer->notifySettingsUnknown()) {
|
||||
return true;
|
||||
} else if (const auto nonDefault = peer->notifySilentPosts()) {
|
||||
return false;
|
||||
}
|
||||
return defaultNotifySettings(peer).settingsUnknown();
|
||||
}
|
||||
|
||||
bool Session::notifySettingsUnknown(not_null<const PeerData*> peer) const {
|
||||
return notifyMuteUnknown(peer) || notifySilentPostsUnknown(peer);
|
||||
}
|
||||
|
||||
rpl::producer<> Session::defaultUserNotifyUpdates() const {
|
||||
return _defaultUserNotifyUpdates.events();
|
||||
}
|
||||
|
||||
rpl::producer<> Session::defaultChatNotifyUpdates() const {
|
||||
return _defaultChatNotifyUpdates.events();
|
||||
}
|
||||
|
||||
rpl::producer<> Session::defaultNotifyUpdates(
|
||||
not_null<const PeerData*> peer) const {
|
||||
return peer->isUser()
|
||||
? defaultUserNotifyUpdates()
|
||||
: defaultChatNotifyUpdates();
|
||||
}
|
||||
|
||||
void Session::forgetMedia() {
|
||||
for (const auto &[id, photo] : _photos) {
|
||||
photo->forget();
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "chat_helpers/stickers.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "data/data_groups.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
class HistoryItem;
|
||||
|
||||
@@ -358,6 +359,26 @@ public:
|
||||
FeedId defaultFeedId() const;
|
||||
rpl::producer<FeedId> defaultFeedIdValue() const;
|
||||
|
||||
void requestNotifySettings(not_null<PeerData*> peer);
|
||||
void applyNotifySetting(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
void updateNotifySettings(
|
||||
not_null<PeerData*> peer,
|
||||
base::optional<int> muteForSeconds,
|
||||
base::optional<bool> silentPosts = base::none);
|
||||
bool notifyIsMuted(
|
||||
not_null<const PeerData*> peer,
|
||||
TimeMs *changesIn = nullptr) const;
|
||||
bool notifySilentPosts(not_null<const PeerData*> peer) const;
|
||||
bool notifyMuteUnknown(not_null<const PeerData*> peer) const;
|
||||
bool notifySilentPostsUnknown(not_null<const PeerData*> peer) const;
|
||||
bool notifySettingsUnknown(not_null<const PeerData*> peer) const;
|
||||
rpl::producer<> defaultUserNotifyUpdates() const;
|
||||
rpl::producer<> defaultChatNotifyUpdates() const;
|
||||
rpl::producer<> defaultNotifyUpdates(
|
||||
not_null<const PeerData*> peer) const;
|
||||
|
||||
void forgetMedia();
|
||||
|
||||
void setMimeForwardIds(MessageIdsList &&list);
|
||||
@@ -453,6 +474,14 @@ private:
|
||||
void clearPinnedDialogs();
|
||||
void setIsPinned(const Dialogs::Key &key, bool pinned);
|
||||
|
||||
NotifySettings &defaultNotifySettings(not_null<const PeerData*> peer);
|
||||
const NotifySettings &defaultNotifySettings(
|
||||
not_null<const PeerData*> peer) const;
|
||||
void unmuteByFinished();
|
||||
void unmuteByFinishedDelayed(TimeMs delay);
|
||||
void updateNotifySettingsLocal(not_null<PeerData*> peer);
|
||||
void sendNotifySettingsUpdates();
|
||||
|
||||
template <typename Method>
|
||||
void enumerateItemViews(
|
||||
not_null<const HistoryItem*> item,
|
||||
@@ -548,6 +577,13 @@ private:
|
||||
|
||||
PeerData *_proxyPromoted = nullptr;
|
||||
|
||||
NotifySettings _defaultUserNotifySettings;
|
||||
NotifySettings _defaultChatNotifySettings;
|
||||
rpl::event_stream<> _defaultUserNotifyUpdates;
|
||||
rpl::event_stream<> _defaultChatNotifyUpdates;
|
||||
std::unordered_set<not_null<const PeerData*>> _mutedPeers;
|
||||
base::Timer _unmuteByFinishedTimer;
|
||||
|
||||
MessageIdsList _mimeForwardIds;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
@@ -106,15 +106,15 @@ FixedBar::FixedBar(
|
||||
, _cancel(this, st::historyAdminLogCancelSearch)
|
||||
, _filter(this, langFactory(lng_admin_log_filter), st::topBarButton) {
|
||||
_backButton->moveToLeft(0, 0);
|
||||
_backButton->setClickedCallback([this] { goBack(); });
|
||||
_filter->setClickedCallback([this] { showFilterSignal.notify(); });
|
||||
_search->setClickedCallback([this] { showSearch(); });
|
||||
_cancel->setClickedCallback([this] { cancelSearch(); });
|
||||
_backButton->setClickedCallback([=] { goBack(); });
|
||||
_filter->setClickedCallback([=] { showFilterSignal.notify(); });
|
||||
_search->setClickedCallback([=] { showSearch(); });
|
||||
_cancel->setClickedCallback([=] { cancelSearch(); });
|
||||
_field->hide();
|
||||
connect(_field, &Ui::FlatInput::cancelled, this, [this] { cancelSearch(); });
|
||||
connect(_field, &Ui::FlatInput::changed, this, [this] { searchUpdated(); });
|
||||
connect(_field, &Ui::FlatInput::submitted, this, [this] { applySearch(); });
|
||||
_searchTimer.setCallback([this] { applySearch(); });
|
||||
connect(_field, &Ui::FlatInput::cancelled, [=] { cancelSearch(); });
|
||||
connect(_field, &Ui::FlatInput::changed, [=] { searchUpdated(); });
|
||||
connect(_field, &Ui::FlatInput::submitted, [=] { applySearch(); });
|
||||
_searchTimer.setCallback([=] { applySearch(); });
|
||||
|
||||
_cancel->hide(anim::type::instant);
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ History::History(const PeerId &peerId)
|
||||
: Entry(this)
|
||||
, peer(App::peer(peerId))
|
||||
, cloudDraftTextCache(st::dialogsTextWidthMin)
|
||||
, _mute(peer->isMuted())
|
||||
, _mute(Auth().data().notifyIsMuted(peer))
|
||||
, _sendActionText(st::dialogsTextWidthMin) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (user->botInfo) {
|
||||
@@ -2194,10 +2194,9 @@ void History::applyDialog(const MTPDdialog &data) {
|
||||
}
|
||||
}
|
||||
}
|
||||
App::main()->applyNotifySetting(
|
||||
Auth().data().applyNotifySetting(
|
||||
MTP_notifyPeer(data.vpeer),
|
||||
data.vnotify_settings,
|
||||
this);
|
||||
data.vnotify_settings);
|
||||
if (data.has_draft() && data.vdraft.type() == mtpc_draftMessage) {
|
||||
Data::applyPeerCloudDraft(peer->id, data.vdraft.c_draftMessage());
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ public:
|
||||
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
|
||||
virtual QString inDialogsText(DrawInDialog way) const;
|
||||
virtual QString inReplyText() const {
|
||||
return notificationText();
|
||||
return inDialogsText(DrawInDialog::WithoutSender);
|
||||
}
|
||||
virtual TextWithEntities originalText() const {
|
||||
return { QString(), EntitiesInText() };
|
||||
|
||||
@@ -149,7 +149,7 @@ bool HistoryMessageReply::updateData(
|
||||
if (replyToMsg) {
|
||||
replyToText.setText(
|
||||
st::messageTextStyle,
|
||||
TextUtilities::Clean(replyToMsg->inReplyText()),
|
||||
replyToMsg->inReplyText(),
|
||||
Ui::DialogTextOptions());
|
||||
|
||||
updateName();
|
||||
@@ -271,14 +271,14 @@ void HistoryMessageReply::paint(
|
||||
p.drawText(x + st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew, y + st::msgReplyPadding.top() + st::msgServiceFont->ascent, replyToVia->text);
|
||||
}
|
||||
|
||||
auto replyToAsMsg = replyToMsg->toHistoryMessage();
|
||||
if (!(flags & PaintFlag::InBubble)) {
|
||||
} else if (!replyToAsMsg) {
|
||||
p.setPen(outbg ? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg) : (selected ? st::msgInDateFgSelected : st::msgInDateFg));
|
||||
} else {
|
||||
if (flags & PaintFlag::InBubble) {
|
||||
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
||||
p.setTextPalette(outbg ? (selected ? st::outReplyTextPaletteSelected : st::outReplyTextPalette) : (selected ? st::inReplyTextPaletteSelected : st::inReplyTextPalette));
|
||||
} else {
|
||||
p.setTextPalette(st::imgReplyTextPalette);
|
||||
}
|
||||
replyToText.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top() + st::msgServiceNameFont->height, w - st::msgReplyBarSkip - previewSkip, w + 2 * x);
|
||||
p.setTextPalette(selected ? (outbg ? st::outTextPaletteSelected : st::inTextPaletteSelected) : (outbg ? st::outTextPalette : st::inTextPalette));
|
||||
}
|
||||
} else {
|
||||
p.setFont(st::msgDateFont);
|
||||
|
||||
@@ -610,7 +610,7 @@ bool HistoryMessage::allowsEdit(TimeId now) const {
|
||||
return true;
|
||||
}
|
||||
if (out()) {
|
||||
return !isPost() || channel->canPublish();
|
||||
return isPost() ? channel->canPublish() : channel->canWrite();
|
||||
}
|
||||
}
|
||||
return out();
|
||||
|
||||
@@ -464,8 +464,11 @@ QString HistoryService::inDialogsText(DrawInDialog way) const {
|
||||
}
|
||||
|
||||
QString HistoryService::inReplyText() const {
|
||||
QString result = HistoryService::notificationText();
|
||||
return result.trimmed().startsWith(author()->name) ? result.trimmed().mid(author()->name.size()).trimmed() : result;
|
||||
const auto result = HistoryService::notificationText();
|
||||
const auto text = result.trimmed().startsWith(author()->name)
|
||||
? result.trimmed().mid(author()->name.size()).trimmed()
|
||||
: result;
|
||||
return textcmdLink(1, text);
|
||||
}
|
||||
|
||||
std::unique_ptr<HistoryView::Element> HistoryService::createView(
|
||||
|
||||
@@ -455,7 +455,7 @@ HistoryWidget::HistoryWidget(
|
||||
connect(_botStart, SIGNAL(clicked()), this, SLOT(onBotStart()));
|
||||
connect(_joinChannel, SIGNAL(clicked()), this, SLOT(onJoinChannel()));
|
||||
connect(_muteUnmute, SIGNAL(clicked()), this, SLOT(onMuteUnmute()));
|
||||
connect(_field, SIGNAL(submitted(bool)), this, SLOT(onSend()));
|
||||
connect(_field, &Ui::InputField::submitted, [=] { send(); });
|
||||
connect(_field, SIGNAL(cancelled()), this, SLOT(onCancel()));
|
||||
connect(_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed()));
|
||||
connect(_field, SIGNAL(resized()), this, SLOT(onFieldResize()));
|
||||
@@ -513,7 +513,7 @@ HistoryWidget::HistoryWidget(
|
||||
_historyDown->installEventFilter(this);
|
||||
_unreadMentions->installEventFilter(this);
|
||||
|
||||
InitMessageField(_field);
|
||||
InitMessageField(controller, _field);
|
||||
_fieldAutocomplete->hide();
|
||||
connect(_fieldAutocomplete, SIGNAL(mentionChosen(UserData*,FieldAutocomplete::ChooseMethod)), this, SLOT(onMentionInsert(UserData*)));
|
||||
connect(_fieldAutocomplete, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod)), this, SLOT(onHashtagOrBotCommandInsert(QString,FieldAutocomplete::ChooseMethod)));
|
||||
@@ -665,7 +665,7 @@ HistoryWidget::HistoryWidget(
|
||||
}
|
||||
}
|
||||
if (update.flags & UpdateFlag::NotificationsEnabled) {
|
||||
updateNotifySettings();
|
||||
updateNotifyControls();
|
||||
}
|
||||
if (update.flags & UpdateFlag::RestrictionReasonChanged) {
|
||||
auto restriction = _peer->restrictionReason();
|
||||
@@ -699,6 +699,12 @@ HistoryWidget::HistoryWidget(
|
||||
}
|
||||
}
|
||||
}));
|
||||
rpl::merge(
|
||||
Auth().data().defaultUserNotifyUpdates(),
|
||||
Auth().data().defaultChatNotifyUpdates()
|
||||
) | rpl::start_with_next([=] {
|
||||
updateNotifyControls();
|
||||
}, lifetime());
|
||||
subscribe(Auth().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) {
|
||||
if (_a_show.animating()
|
||||
|| _history != query.item->history()
|
||||
@@ -997,10 +1003,7 @@ void HistoryWidget::onMentionInsert(UserData *user) {
|
||||
if (replacement.isEmpty()) {
|
||||
replacement = App::peerName(user);
|
||||
}
|
||||
entityTag = qsl("mention://user.")
|
||||
+ QString::number(user->bareId())
|
||||
+ '.'
|
||||
+ QString::number(user->accessHash());
|
||||
entityTag = PrepareMentionTag(user);
|
||||
} else {
|
||||
replacement = '@' + user->username;
|
||||
}
|
||||
@@ -1139,8 +1142,10 @@ void HistoryWidget::updateStickersByEmoji() {
|
||||
}
|
||||
|
||||
void HistoryWidget::onTextChange() {
|
||||
updateInlineBotQuery();
|
||||
updateStickersByEmoji();
|
||||
InvokeQueued(this, [=] {
|
||||
updateInlineBotQuery();
|
||||
updateStickersByEmoji();
|
||||
});
|
||||
|
||||
if (_history) {
|
||||
if (!_inlineBot
|
||||
@@ -1172,8 +1177,8 @@ void HistoryWidget::onDraftSaveDelayed() {
|
||||
if (!_peer || !(_textUpdateEvents & TextUpdateEvent::SaveDraft)) {
|
||||
return;
|
||||
}
|
||||
if (!_field->textCursor().anchor()
|
||||
&& !_field->textCursor().position()
|
||||
if (!_field->textCursor().position()
|
||||
&& !_field->textCursor().anchor()
|
||||
&& !_field->scrollTop().current()) {
|
||||
if (!Local::hasDraftCursors(_peer->id)) {
|
||||
return;
|
||||
@@ -1637,6 +1642,8 @@ void HistoryWidget::fastShowAtEnd(not_null<History*> history) {
|
||||
}
|
||||
|
||||
void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
||||
InvokeQueued(this, [=] { updateStickersByEmoji(); });
|
||||
|
||||
auto draft = _history ? _history->draft() : nullptr;
|
||||
auto fieldAvailable = canWriteMessage();
|
||||
if (!draft || (!_history->editDraft() && !fieldAvailable)) {
|
||||
@@ -1847,10 +1854,8 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
|
||||
updateTopBarSelection();
|
||||
|
||||
if (_channel) {
|
||||
updateNotifySettings();
|
||||
if (_peer->notifySettingsUnknown()) {
|
||||
Auth().api().requestNotifySetting(_peer);
|
||||
}
|
||||
updateNotifyControls();
|
||||
Auth().data().requestNotifySettings(_peer);
|
||||
refreshSilentToggle();
|
||||
}
|
||||
|
||||
@@ -1954,15 +1959,15 @@ void HistoryWidget::updateFieldSubmitSettings() {
|
||||
_field->setSubmitSettings(settings);
|
||||
}
|
||||
|
||||
void HistoryWidget::updateNotifySettings() {
|
||||
void HistoryWidget::updateNotifyControls() {
|
||||
if (!_peer || !_peer->isChannel()) return;
|
||||
|
||||
_muteUnmute->setText(lang(_history->mute()
|
||||
? lng_channel_unmute
|
||||
: lng_channel_mute).toUpper());
|
||||
if (!_peer->notifySettingsUnknown()) {
|
||||
if (!Auth().data().notifySilentPostsUnknown(_peer)) {
|
||||
if (_silent) {
|
||||
_silent->setChecked(_peer->notifySilentPosts());
|
||||
_silent->setChecked(Auth().data().notifySilentPosts(_peer));
|
||||
} else if (hasSilentToggle()) {
|
||||
refreshSilentToggle();
|
||||
updateControlsGeometry();
|
||||
@@ -2886,17 +2891,26 @@ void HistoryWidget::showNextUnreadMention() {
|
||||
void HistoryWidget::saveEditMsg() {
|
||||
if (_saveEditMsgRequestId) return;
|
||||
|
||||
WebPageId webPageId = _previewCancelled ? CancelledWebPageId : ((_previewData && _previewData->pendingTill >= 0) ? _previewData->id : 0);
|
||||
const auto webPageId = _previewCancelled
|
||||
? CancelledWebPageId
|
||||
: ((_previewData && _previewData->pendingTill >= 0)
|
||||
? _previewData->id
|
||||
: WebPageId(0));
|
||||
|
||||
auto &textWithTags = _field->getTextWithTags();
|
||||
auto prepareFlags = Ui::ItemTextOptions(_history, App::self()).flags;
|
||||
const auto textWithTags = _field->getTextWithAppliedMarkdown();
|
||||
const auto prepareFlags = Ui::ItemTextOptions(_history, App::self()).flags;
|
||||
auto sending = TextWithEntities();
|
||||
auto left = TextWithEntities { textWithTags.text, ConvertTextTagsToEntities(textWithTags.tags) };
|
||||
TextUtilities::PrepareForSending(left, prepareFlags);
|
||||
|
||||
if (!TextUtilities::CutPart(sending, left, MaxMessageSize)) {
|
||||
_field->selectAll();
|
||||
_field->setFocus();
|
||||
if (const auto item = App::histItemById(_channel, _editMsgId)) {
|
||||
const auto suggestModerateActions = false;
|
||||
Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions));
|
||||
} else {
|
||||
_field->selectAll();
|
||||
_field->setFocus();
|
||||
}
|
||||
return;
|
||||
} else if (!left.text.isEmpty()) {
|
||||
Ui::show(Box<InformBox>(lang(lng_edit_too_long)));
|
||||
@@ -2919,6 +2933,7 @@ void HistoryWidget::saveEditMsg() {
|
||||
_history->peer->input,
|
||||
MTP_int(_editMsgId),
|
||||
MTP_string(sending.text),
|
||||
MTPInputMedia(),
|
||||
MTPnullMarkup,
|
||||
sentEntities,
|
||||
MTP_inputGeoPointEmpty()),
|
||||
@@ -2978,7 +2993,7 @@ void HistoryWidget::hideSelectorControlsAnimated() {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::onSend() {
|
||||
void HistoryWidget::send() {
|
||||
if (!_history) return;
|
||||
|
||||
if (_editMsgId) {
|
||||
@@ -2989,7 +3004,7 @@ void HistoryWidget::onSend() {
|
||||
WebPageId webPageId = _previewCancelled ? CancelledWebPageId : ((_previewData && _previewData->pendingTill >= 0) ? _previewData->id : 0);
|
||||
|
||||
auto message = MainWidget::MessageToSend(_history);
|
||||
message.textWithTags = _field->getTextWithTags();
|
||||
message.textWithTags = _field->getTextWithAppliedMarkdown();
|
||||
message.replyTo = replyToId();
|
||||
message.webPageId = webPageId;
|
||||
App::main()->sendMessage(message);
|
||||
@@ -3072,10 +3087,10 @@ void HistoryWidget::onJoinChannel() {
|
||||
}
|
||||
|
||||
void HistoryWidget::onMuteUnmute() {
|
||||
const auto muteState = _history->mute()
|
||||
? Data::NotifySettings::MuteChange::Unmute
|
||||
: Data::NotifySettings::MuteChange::Mute;
|
||||
App::main()->updateNotifySettings(_peer, muteState);
|
||||
const auto muteForSeconds = _history->mute()
|
||||
? 0
|
||||
: Data::NotifySettings::kDefaultMutePeriod;
|
||||
Auth().data().updateNotifySettings(_peer, muteForSeconds);
|
||||
}
|
||||
|
||||
void HistoryWidget::onBroadcastSilentChange() {
|
||||
@@ -3243,7 +3258,7 @@ void HistoryWidget::sendButtonClicked() {
|
||||
if (type == Ui::SendButton::Type::Cancel) {
|
||||
onInlineBotCancel();
|
||||
} else if (type != Ui::SendButton::Type::Record) {
|
||||
onSend();
|
||||
send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3627,7 +3642,7 @@ bool HistoryWidget::hasSilentToggle() const {
|
||||
&& _peer->isChannel()
|
||||
&& !_peer->isMegagroup()
|
||||
&& _peer->canWrite()
|
||||
&& !_peer->notifySettingsUnknown();
|
||||
&& !Auth().data().notifySilentPostsUnknown(_peer);
|
||||
}
|
||||
|
||||
void HistoryWidget::inlineBotResolveDone(
|
||||
@@ -3787,12 +3802,7 @@ void HistoryWidget::onKbToggle(bool manual) {
|
||||
_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard->forceReply()) ? App::histItemById(_keyboard->forMsgId()) : 0;
|
||||
if (_kbReplyTo && !_editMsgId && !_replyToId && fieldEnabled) {
|
||||
updateReplyToName();
|
||||
_replyEditMsgText.setText(
|
||||
st::messageTextStyle,
|
||||
TextUtilities::Clean(_kbReplyTo->inReplyText()),
|
||||
Ui::DialogTextOptions());
|
||||
_fieldBarCancel->show();
|
||||
updateMouseTracking();
|
||||
updateReplyEditText(_kbReplyTo);
|
||||
}
|
||||
if (manual && _history) {
|
||||
_history->lastKeyboardHiddenId = 0;
|
||||
@@ -3809,12 +3819,7 @@ void HistoryWidget::onKbToggle(bool manual) {
|
||||
_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard->forceReply()) ? App::histItemById(_keyboard->forMsgId()) : 0;
|
||||
if (_kbReplyTo && !_editMsgId && !_replyToId) {
|
||||
updateReplyToName();
|
||||
_replyEditMsgText.setText(
|
||||
st::messageTextStyle,
|
||||
TextUtilities::Clean(_kbReplyTo->inReplyText()),
|
||||
Ui::DialogTextOptions());
|
||||
_fieldBarCancel->show();
|
||||
updateMouseTracking();
|
||||
updateReplyEditText(_kbReplyTo);
|
||||
}
|
||||
if (manual && _history) {
|
||||
_history->lastKeyboardHiddenId = 0;
|
||||
@@ -4088,7 +4093,7 @@ void HistoryWidget::updateFieldPlaceholder() {
|
||||
const auto peer = _history ? _history->peer.get() : nullptr;
|
||||
_field->setPlaceholder(langFactory(
|
||||
(peer && peer->isChannel() && !peer->isMegagroup())
|
||||
? (peer->notifySilentPosts()
|
||||
? (Auth().data().notifySilentPosts(peer)
|
||||
? lng_broadcast_silent_ph
|
||||
: lng_broadcast_ph)
|
||||
: lng_message_ph));
|
||||
@@ -4168,6 +4173,7 @@ bool HistoryWidget::confirmSendingFiles(
|
||||
const auto anchor = cursor.anchor();
|
||||
const auto text = _field->getTextWithTags();
|
||||
auto box = Box<SendFilesBox>(
|
||||
controller(),
|
||||
std::move(list),
|
||||
text,
|
||||
boxCompressConfirm);
|
||||
@@ -4405,7 +4411,9 @@ void HistoryWidget::sendFileConfirmed(
|
||||
flags |= MTPDmessage::Flag::f_grouped_id;
|
||||
}
|
||||
auto messageFromId = channelPost ? 0 : Auth().userId();
|
||||
auto messagePostAuthor = channelPost ? (Auth().user()->firstName + ' ' + Auth().user()->lastName) : QString();
|
||||
auto messagePostAuthor = channelPost
|
||||
? App::peerName(Auth().user())
|
||||
: QString();
|
||||
if (file->type == SendMediaType::Photo) {
|
||||
auto photoFlags = MTPDmessageMediaPhoto::Flag::f_photo | 0;
|
||||
auto photo = MTP_messageMediaPhoto(
|
||||
@@ -5089,12 +5097,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
||||
_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard->forceReply()) ? App::histItemById(_keyboard->forMsgId()) : 0;
|
||||
if (_kbReplyTo && !_replyToId) {
|
||||
updateReplyToName();
|
||||
_replyEditMsgText.setText(
|
||||
st::messageTextStyle,
|
||||
TextUtilities::Clean(_kbReplyTo->inReplyText()),
|
||||
Ui::DialogTextOptions());
|
||||
_fieldBarCancel->show();
|
||||
updateMouseTracking();
|
||||
updateReplyEditText(_kbReplyTo);
|
||||
}
|
||||
} else {
|
||||
if (!_a_show.animating()) {
|
||||
@@ -5378,7 +5381,7 @@ void HistoryWidget::onInlineResultSend(
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
bool channelPost = _peer->isChannel() && !_peer->isMegagroup();
|
||||
bool silentPost = channelPost && _peer->notifySilentPosts();
|
||||
bool silentPost = channelPost && Auth().data().notifySilentPosts(_peer);
|
||||
if (channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
@@ -5396,7 +5399,9 @@ void HistoryWidget::onInlineResultSend(
|
||||
}
|
||||
|
||||
auto messageFromId = channelPost ? 0 : Auth().userId();
|
||||
auto messagePostAuthor = channelPost ? (Auth().user()->firstName + ' ' + Auth().user()->lastName) : QString();
|
||||
auto messagePostAuthor = channelPost
|
||||
? App::peerName(Auth().user())
|
||||
: QString();
|
||||
MTPint messageDate = MTP_int(unixtime());
|
||||
UserId messageViaBotId = bot ? peerToUser(bot->id) : 0;
|
||||
MsgId messageId = newId.msg;
|
||||
@@ -5587,7 +5592,7 @@ bool HistoryWidget::sendExistingDocument(
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
bool channelPost = _peer->isChannel() && !_peer->isMegagroup();
|
||||
bool silentPost = channelPost && _peer->notifySilentPosts();
|
||||
bool silentPost = channelPost && Auth().data().notifySilentPosts(_peer);
|
||||
if (channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
@@ -5601,7 +5606,8 @@ bool HistoryWidget::sendExistingDocument(
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
auto messageFromId = channelPost ? 0 : Auth().userId();
|
||||
auto messagePostAuthor = channelPost ? (Auth().user()->firstName + ' ' + Auth().user()->lastName) : QString();
|
||||
auto messagePostAuthor = channelPost
|
||||
? App::peerName(Auth().user()) : QString();
|
||||
|
||||
TextUtilities::Trim(caption);
|
||||
auto sentEntities = TextUtilities::EntitiesToMTP(
|
||||
@@ -5683,7 +5689,7 @@ void HistoryWidget::sendExistingPhoto(
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
bool channelPost = _peer->isChannel() && !_peer->isMegagroup();
|
||||
bool silentPost = channelPost && _peer->notifySilentPosts();
|
||||
bool silentPost = channelPost && Auth().data().notifySilentPosts(_peer);
|
||||
if (channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
@@ -5697,7 +5703,9 @@ void HistoryWidget::sendExistingPhoto(
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
auto messageFromId = channelPost ? 0 : Auth().userId();
|
||||
auto messagePostAuthor = channelPost ? (Auth().user()->firstName + ' ' + Auth().user()->lastName) : QString();
|
||||
auto messagePostAuthor = channelPost
|
||||
? App::peerName(Auth().user())
|
||||
: QString();
|
||||
|
||||
TextUtilities::Trim(caption);
|
||||
auto sentEntities = TextUtilities::EntitiesToMTP(
|
||||
@@ -5816,15 +5824,8 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
||||
} else {
|
||||
_replyEditMsg = item;
|
||||
_replyToId = item->id;
|
||||
_replyEditMsgText.setText(
|
||||
st::messageTextStyle,
|
||||
TextUtilities::Clean(_replyEditMsg->inReplyText()),
|
||||
Ui::DialogTextOptions());
|
||||
|
||||
updateReplyEditText(_replyEditMsg);
|
||||
updateBotKeyboard();
|
||||
|
||||
if (!_field->isHidden()) _fieldBarCancel->show();
|
||||
updateMouseTracking();
|
||||
updateReplyToName();
|
||||
updateControlsGeometry();
|
||||
updateField();
|
||||
@@ -5846,7 +5847,7 @@ void HistoryWidget::editMessage(FullMsgId itemId) {
|
||||
void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
|
||||
if (const auto media = item->media()) {
|
||||
if (media->allowsEditCaption()) {
|
||||
Ui::show(Box<EditCaptionBox>(item));
|
||||
Ui::show(Box<EditCaptionBox>(controller(), item));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -6274,10 +6275,13 @@ void HistoryWidget::onCancel() {
|
||||
lang(lng_cancel_edit_post_yes),
|
||||
lang(lng_cancel_edit_post_no),
|
||||
base::lambda_guarded(this, [this] {
|
||||
onFieldBarCancel();
|
||||
})));
|
||||
if (_editMsgId) {
|
||||
cancelEdit();
|
||||
Ui::hideLayer();
|
||||
}
|
||||
})));
|
||||
} else {
|
||||
onFieldBarCancel();
|
||||
cancelEdit();
|
||||
}
|
||||
} else if (!_fieldAutocomplete->isHidden()) {
|
||||
_fieldAutocomplete->hideAnimated();
|
||||
@@ -6445,6 +6449,17 @@ void HistoryWidget::messageDataReceived(ChannelData *channel, MsgId msgId) {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::updateReplyEditText(not_null<HistoryItem*> item) {
|
||||
_replyEditMsgText.setText(
|
||||
st::messageTextStyle,
|
||||
item->inReplyText(),
|
||||
Ui::DialogTextOptions());
|
||||
if (!_field->isHidden() || _recording) {
|
||||
_fieldBarCancel->show();
|
||||
updateMouseTracking();
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::updateReplyEditTexts(bool force) {
|
||||
if (!force) {
|
||||
if (_replyEditMsg || (!_editMsgId && !_replyToId)) {
|
||||
@@ -6455,17 +6470,8 @@ void HistoryWidget::updateReplyEditTexts(bool force) {
|
||||
_replyEditMsg = App::histItemById(_channel, _editMsgId ? _editMsgId : _replyToId);
|
||||
}
|
||||
if (_replyEditMsg) {
|
||||
_replyEditMsgText.setText(
|
||||
st::messageTextStyle,
|
||||
TextUtilities::Clean(_replyEditMsg->inReplyText()),
|
||||
Ui::DialogTextOptions());
|
||||
|
||||
updateReplyEditText(_replyEditMsg);
|
||||
updateBotKeyboard();
|
||||
|
||||
if (!_field->isHidden() || _recording) {
|
||||
_fieldBarCancel->show();
|
||||
updateMouseTracking();
|
||||
}
|
||||
updateReplyToName();
|
||||
updateField();
|
||||
} else if (force) {
|
||||
@@ -6514,13 +6520,13 @@ void HistoryWidget::updateForwardingTexts() {
|
||||
if (count < 2) {
|
||||
text = _toForward.front()->inReplyText();
|
||||
} else {
|
||||
text = lng_forward_messages(lt_count, count);
|
||||
text = textcmdLink(1, lng_forward_messages(lt_count, count));
|
||||
}
|
||||
}
|
||||
_toForwardFrom.setText(st::msgNameStyle, from, Ui::NameTextOptions());
|
||||
_toForwardText.setText(
|
||||
st::messageTextStyle,
|
||||
TextUtilities::Clean(text),
|
||||
text,
|
||||
Ui::DialogTextOptions());
|
||||
_toForwardNameVersion = version;
|
||||
}
|
||||
@@ -6592,8 +6598,10 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||
} else {
|
||||
_replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
|
||||
}
|
||||
p.setPen(!drawMsgText->toHistoryMessage() ? st::historyComposeAreaFgService : st::historyComposeAreaFg);
|
||||
p.setPen(st::historyComposeAreaFg);
|
||||
p.setTextPalette(st::historyComposeAreaPalette);
|
||||
_replyEditMsgText.drawElided(p, replyLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
|
||||
p.restoreTextPalette();
|
||||
} else {
|
||||
p.setFont(st::msgDateFont);
|
||||
p.setPen(st::historyComposeAreaFgService);
|
||||
@@ -6624,8 +6632,10 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||
}
|
||||
p.setPen(st::historyReplyNameFg);
|
||||
_toForwardFrom.drawElided(p, forwardLeft, backy + st::msgReplyPadding.top(), width() - forwardLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
|
||||
p.setPen(serviceColor ? st::historyComposeAreaFgService : st::historyComposeAreaFg);
|
||||
p.setPen(st::historyComposeAreaFg);
|
||||
p.setTextPalette(st::historyComposeAreaPalette);
|
||||
_toForwardText.drawElided(p, forwardLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - forwardLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
|
||||
p.restoreTextPalette();
|
||||
}
|
||||
}
|
||||
if (drawWebPagePreview) {
|
||||
|
||||
@@ -318,7 +318,7 @@ public:
|
||||
|
||||
void setInnerFocus();
|
||||
|
||||
void updateNotifySettings();
|
||||
void updateNotifyControls();
|
||||
|
||||
void saveGif(DocumentData *doc);
|
||||
|
||||
@@ -433,8 +433,6 @@ public slots:
|
||||
void preloadHistoryIfNeeded();
|
||||
|
||||
private slots:
|
||||
void onSend();
|
||||
|
||||
void onHashtagOrBotCommandInsert(QString str, FieldAutocomplete::ChooseMethod method);
|
||||
void onMentionInsert(UserData *user);
|
||||
void onInlineBotCancel();
|
||||
@@ -449,6 +447,7 @@ private:
|
||||
using TabbedSelector = ChatHelpers::TabbedSelector;
|
||||
using DragState = Storage::MimeDataState;
|
||||
|
||||
void send();
|
||||
void handlePendingHistoryUpdate();
|
||||
void fullPeerUpdated(PeerData *peer);
|
||||
void toggleTabbedSelectorMode();
|
||||
@@ -571,6 +570,7 @@ private:
|
||||
|
||||
object_ptr<Ui::IconButton> _fieldBarCancel;
|
||||
void updateReplyEditTexts(bool force = false);
|
||||
void updateReplyEditText(not_null<HistoryItem*> item);
|
||||
|
||||
struct PinnedBar {
|
||||
PinnedBar(MsgId msgId, HistoryWidget *parent);
|
||||
|
||||
@@ -1349,7 +1349,11 @@ bool Message::displayFastShare() const {
|
||||
if (peer->isChannel()) {
|
||||
return !peer->isMegagroup();
|
||||
} else if (const auto user = peer->asUser()) {
|
||||
if (user->botInfo && !item->out()) {
|
||||
if (const auto forwarded = item->Get<HistoryMessageForwarded>()) {
|
||||
return !peer->isSelf()
|
||||
&& forwarded->originalSender->isChannel()
|
||||
&& !forwarded->originalSender->isMegagroup();
|
||||
} else if (user->botInfo && !item->out()) {
|
||||
if (const auto media = this->media()) {
|
||||
return media->allowsFastShare();
|
||||
}
|
||||
|
||||
@@ -212,18 +212,17 @@ base::unique_qptr<Ui::PopupMenu> ChannelsController::rowContextMenu(
|
||||
void NotificationsController::Start(not_null<Data::Feed*> feed) {
|
||||
const auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->addButton(langFactory(lng_settings_save), [=] {
|
||||
const auto main = App::main();
|
||||
const auto count = box->peerListFullRowsCount();
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
const auto row = box->peerListRowAt(i);
|
||||
const auto peer = row->peer();
|
||||
const auto muted = !row->checked();
|
||||
if (muted != peer->isMuted()) {
|
||||
main->updateNotifySettings(
|
||||
if (muted != Auth().data().notifyIsMuted(peer)) {
|
||||
Auth().data().updateNotifySettings(
|
||||
peer,
|
||||
(muted
|
||||
? Data::NotifySettings::MuteChange::Mute
|
||||
: Data::NotifySettings::MuteChange::Unmute));
|
||||
? Data::NotifySettings::kDefaultMutePeriod
|
||||
: 0));
|
||||
}
|
||||
}
|
||||
box->closeBox();
|
||||
@@ -320,7 +319,7 @@ void NotificationsController::applyFeedDialogs(
|
||||
auto notMutedChannels = ranges::view::all(
|
||||
channels
|
||||
) | ranges::view::filter([](not_null<ChannelData*> channel) {
|
||||
return !channel->isMuted();
|
||||
return !Auth().data().notifyIsMuted(channel);
|
||||
});
|
||||
delegate()->peerListAddSelectedRows(notMutedChannels);
|
||||
for (const auto channel : channels) {
|
||||
|
||||
@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "auth_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "mainwidget.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_info.h"
|
||||
@@ -449,10 +450,10 @@ void WrapWidget::addProfileNotificationsButton() {
|
||||
? st::infoLayerTopBarNotifications
|
||||
: st::infoTopBarNotifications)));
|
||||
notifications->addClickHandler([peer] {
|
||||
const auto muteState = peer->isMuted()
|
||||
? Data::NotifySettings::MuteChange::Unmute
|
||||
: Data::NotifySettings::MuteChange::Mute;
|
||||
App::main()->updateNotifySettings(peer, muteState);
|
||||
const auto muteForSeconds = Auth().data().notifyIsMuted(peer)
|
||||
? 0
|
||||
: Data::NotifySettings::kDefaultMutePeriod;
|
||||
Auth().data().updateNotifySettings(peer, muteForSeconds);
|
||||
});
|
||||
Profile::NotificationsEnabledValue(
|
||||
peer
|
||||
|
||||
@@ -310,10 +310,10 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupMuteToggle() {
|
||||
result->toggleOn(
|
||||
NotificationsEnabledValue(peer)
|
||||
)->addClickHandler([=] {
|
||||
const auto muteState = peer->isMuted()
|
||||
? Data::NotifySettings::MuteChange::Unmute
|
||||
: Data::NotifySettings::MuteChange::Mute;
|
||||
App::main()->updateNotifySettings(peer, muteState);
|
||||
const auto muteForSeconds = Auth().data().notifyIsMuted(peer)
|
||||
? 0
|
||||
: Data::NotifySettings::kDefaultMutePeriod;
|
||||
Auth().data().updateNotifySettings(peer, muteForSeconds);
|
||||
});
|
||||
object_ptr<FloatingIcon>(
|
||||
result,
|
||||
@@ -537,6 +537,7 @@ void ActionsFiller::addBotCommandActions(not_null<UserData*> user) {
|
||||
};
|
||||
addBotCommand(lng_profile_bot_help, qsl("help"));
|
||||
addBotCommand(lng_profile_bot_settings, qsl("settings"));
|
||||
addBotCommand(lng_profile_bot_privacy, qsl("privacy"));
|
||||
}
|
||||
|
||||
void ActionsFiller::addReportAction() {
|
||||
|
||||
@@ -115,11 +115,14 @@ rpl::producer<QString> LinkValue(
|
||||
|
||||
rpl::producer<bool> NotificationsEnabledValue(
|
||||
not_null<PeerData*> peer) {
|
||||
return Notify::PeerUpdateValue(
|
||||
return rpl::merge(
|
||||
Notify::PeerUpdateValue(
|
||||
peer,
|
||||
Notify::PeerUpdate::Flag::NotificationsEnabled
|
||||
) | rpl::map([] { return rpl::empty_value(); }),
|
||||
Auth().data().defaultNotifyUpdates(peer)
|
||||
) | rpl::map([peer] {
|
||||
return !peer->isMuted();
|
||||
return !Auth().data().notifyIsMuted(peer);
|
||||
}) | rpl::distinct_until_changed();
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,15 @@ introResetButton: RoundButton(defaultLightButton) {
|
||||
}
|
||||
introResetBottom: 20px;
|
||||
|
||||
introTermsLabel: FlatLabel(defaultFlatLabel) {
|
||||
align: align(top);
|
||||
}
|
||||
introTermsBottom: 20px;
|
||||
introTermsContent: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 285px;
|
||||
}
|
||||
introTermsPadding: margins(23px, 0px, 16px, 0px);
|
||||
|
||||
introCountryIcon: icon {{ "intro_country_dropdown", menuIconFg }};
|
||||
introCountryIconPosition: point(8px, 37px);
|
||||
|
||||
|
||||
@@ -48,6 +48,15 @@ Locale: ") + Platform::SystemLanguage();
|
||||
UrlClickHandler::doOpen(url);
|
||||
}
|
||||
|
||||
bool TermsAcceptRequired(const QString &countryCode) {
|
||||
const auto codes = std::vector<QString>{
|
||||
"AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE",
|
||||
"GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL", "PL", "PT",
|
||||
"RO", "SK", "SI", "ES", "SE", "GB"
|
||||
};
|
||||
return ranges::find(codes, countryCode.toUpper()) != end(codes);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PhoneWidget::PhoneWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
|
||||
@@ -64,6 +73,16 @@ PhoneWidget::PhoneWidget(QWidget *parent, Widget::Data *data) : Step(parent, dat
|
||||
connect(_phone, SIGNAL(changed()), this, SLOT(onInputChange()));
|
||||
connect(_code, SIGNAL(changed()), this, SLOT(onInputChange()));
|
||||
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
||||
connect(
|
||||
_code,
|
||||
&Ui::CountryCodeInput::codeChanged,
|
||||
this,
|
||||
&PhoneWidget::toggleTerms);
|
||||
connect(
|
||||
_country,
|
||||
&CountryInput::codeChanged,
|
||||
this,
|
||||
&PhoneWidget::toggleTerms);
|
||||
|
||||
setTitleText(langFactory(lng_phone_title));
|
||||
setDescriptionText(langFactory(lng_phone_desc));
|
||||
@@ -75,6 +94,10 @@ PhoneWidget::PhoneWidget(QWidget *parent, Widget::Data *data) : Step(parent, dat
|
||||
}
|
||||
_changed = false;
|
||||
|
||||
subscribe(Lang::Current().updated(), [this] {
|
||||
_termsAccepted = false;
|
||||
});
|
||||
|
||||
Messenger::Instance().destroyStaleAuthorizationKeys();
|
||||
}
|
||||
|
||||
@@ -106,22 +129,22 @@ void PhoneWidget::hidePhoneError() {
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneWidget::showSignup() {
|
||||
showPhoneError(langFactory(lng_bad_phone_noreg));
|
||||
if (!_signup) {
|
||||
auto signupText = lng_phone_notreg(lt_link_start, textcmdStartLink(1), lt_link_end, textcmdStopLink(), lt_signup_start, textcmdStartLink(2), lt_signup_end, textcmdStopLink());
|
||||
auto inner = object_ptr<Ui::FlatLabel>(this, signupText, Ui::FlatLabel::InitType::Rich, st::introDescription);
|
||||
_signup.create(this, std::move(inner));
|
||||
_signup->entity()->setLink(1, std::make_shared<UrlClickHandler>(qsl("https://telegram.org"), false));
|
||||
_signup->entity()->setLink(2, std::make_shared<LambdaClickHandler>([this] {
|
||||
toSignUp();
|
||||
}));
|
||||
_signup->hide(anim::type::instant);
|
||||
updateSignupGeometry();
|
||||
}
|
||||
_signup->show(anim::type::normal);
|
||||
hideDescription();
|
||||
}
|
||||
//void PhoneWidget::showSignup() {
|
||||
// showPhoneError(langFactory(lng_bad_phone_noreg));
|
||||
// if (!_signup) {
|
||||
// auto signupText = lng_phone_notreg(lt_link_start, textcmdStartLink(1), lt_link_end, textcmdStopLink(), lt_signup_start, textcmdStartLink(2), lt_signup_end, textcmdStopLink());
|
||||
// auto inner = object_ptr<Ui::FlatLabel>(this, signupText, Ui::FlatLabel::InitType::Rich, st::introDescription);
|
||||
// _signup.create(this, std::move(inner));
|
||||
// _signup->entity()->setLink(1, std::make_shared<UrlClickHandler>(qsl("https://telegram.org"), false));
|
||||
// _signup->entity()->setLink(2, std::make_shared<LambdaClickHandler>([this] {
|
||||
// toSignUp();
|
||||
// }));
|
||||
// _signup->hide(anim::type::instant);
|
||||
// updateSignupGeometry();
|
||||
// }
|
||||
// _signup->show(anim::type::normal);
|
||||
// hideDescription();
|
||||
//}
|
||||
|
||||
void PhoneWidget::countryChanged() {
|
||||
if (!_changed) {
|
||||
@@ -129,6 +152,13 @@ void PhoneWidget::countryChanged() {
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneWidget::toggleTerms() {
|
||||
_termsAccepted = false;
|
||||
InvokeQueued(this, [=] {
|
||||
Step::toggleTerms(_country->iso());
|
||||
});
|
||||
}
|
||||
|
||||
void PhoneWidget::onInputChange() {
|
||||
_changed = true;
|
||||
hidePhoneError();
|
||||
@@ -143,13 +173,33 @@ void PhoneWidget::submit() {
|
||||
return;
|
||||
}
|
||||
|
||||
hidePhoneError();
|
||||
const auto sendCode = [=] {
|
||||
hidePhoneError();
|
||||
|
||||
_checkRequest->start(1000);
|
||||
_checkRequest->start(1000);
|
||||
|
||||
_sentPhone = fullNumber();
|
||||
Messenger::Instance().mtp()->setUserPhone(_sentPhone);
|
||||
_sentRequest = MTP::send(MTPauth_CheckPhone(MTP_string(_sentPhone)), rpcDone(&PhoneWidget::phoneCheckDone), rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||
_sentPhone = fullNumber();
|
||||
Messenger::Instance().mtp()->setUserPhone(_sentPhone);
|
||||
//_sentRequest = MTP::send(MTPauth_CheckPhone(MTP_string(_sentPhone)), rpcDone(&PhoneWidget::phoneCheckDone), rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||
_sentRequest = MTP::send(
|
||||
MTPauth_SendCode(
|
||||
MTP_flags(0),
|
||||
MTP_string(_sentPhone),
|
||||
MTPBool(),
|
||||
MTP_int(ApiId),
|
||||
MTP_string(ApiHash)),
|
||||
rpcDone(&PhoneWidget::phoneSubmitDone),
|
||||
rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||
};
|
||||
const auto code = _country->iso();
|
||||
if (true || !TermsAcceptRequired(code) || _termsAccepted) {
|
||||
sendCode();
|
||||
} else {
|
||||
acceptTerms(code, base::lambda_guarded(this, [=] {
|
||||
_termsAccepted = true;
|
||||
sendCode();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneWidget::stopCheck() {
|
||||
@@ -168,22 +218,22 @@ void PhoneWidget::onCheckRequest() {
|
||||
stopCheck();
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneWidget::phoneCheckDone(const MTPauth_CheckedPhone &result) {
|
||||
stopCheck();
|
||||
|
||||
auto &d = result.c_auth_checkedPhone();
|
||||
if (mtpIsTrue(d.vphone_registered)) {
|
||||
hidePhoneError();
|
||||
|
||||
_checkRequest->start(1000);
|
||||
|
||||
_sentRequest = MTP::send(MTPauth_SendCode(MTP_flags(0), MTP_string(_sentPhone), MTPBool(), MTP_int(ApiId), MTP_string(ApiHash)), rpcDone(&PhoneWidget::phoneSubmitDone), rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||
} else {
|
||||
showSignup();
|
||||
_sentRequest = 0;
|
||||
}
|
||||
}
|
||||
//
|
||||
//void PhoneWidget::phoneCheckDone(const MTPauth_CheckedPhone &result) {
|
||||
// stopCheck();
|
||||
//
|
||||
// auto &d = result.c_auth_checkedPhone();
|
||||
// if (mtpIsTrue(d.vphone_registered)) {
|
||||
// hidePhoneError();
|
||||
//
|
||||
// _checkRequest->start(1000);
|
||||
//
|
||||
// _sentRequest = MTP::send(MTPauth_SendCode(MTP_flags(0), MTP_string(_sentPhone), MTPBool(), MTP_int(ApiId), MTP_string(ApiHash)), rpcDone(&PhoneWidget::phoneSubmitDone), rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||
// } else {
|
||||
// showSignup();
|
||||
// _sentRequest = 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
void PhoneWidget::phoneSubmitDone(const MTPauth_SentCode &result) {
|
||||
stopCheck();
|
||||
@@ -209,13 +259,13 @@ void PhoneWidget::phoneSubmitDone(const MTPauth_SentCode &result) {
|
||||
goNext(new Intro::CodeWidget(parentWidget(), getData()));
|
||||
}
|
||||
|
||||
void PhoneWidget::toSignUp() {
|
||||
hideError(); // Hide error, but leave the signup label visible.
|
||||
|
||||
_checkRequest->start(1000);
|
||||
|
||||
_sentRequest = MTP::send(MTPauth_SendCode(MTP_flags(0), MTP_string(_sentPhone), MTPBool(), MTP_int(ApiId), MTP_string(ApiHash)), rpcDone(&PhoneWidget::phoneSubmitDone), rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||
}
|
||||
//void PhoneWidget::toSignUp() {
|
||||
// hideError(); // Hide error, but leave the signup label visible.
|
||||
//
|
||||
// _checkRequest->start(1000);
|
||||
//
|
||||
// _sentRequest = MTP::send(MTPauth_SendCode(MTP_flags(0), MTP_string(_sentPhone), MTPBool(), MTP_int(ApiId), MTP_string(ApiHash)), rpcDone(&PhoneWidget::phoneSubmitDone), rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||
//}
|
||||
|
||||
bool PhoneWidget::phoneSubmitFail(const RPCError &error) {
|
||||
if (MTP::isFloodError(error)) {
|
||||
|
||||
@@ -47,25 +47,27 @@ private slots:
|
||||
private:
|
||||
void updateSignupGeometry();
|
||||
void countryChanged();
|
||||
void toggleTerms();
|
||||
|
||||
void phoneCheckDone(const MTPauth_CheckedPhone &result);
|
||||
//void phoneCheckDone(const MTPauth_CheckedPhone &result);
|
||||
void phoneSubmitDone(const MTPauth_SentCode &result);
|
||||
bool phoneSubmitFail(const RPCError &error);
|
||||
|
||||
void toSignUp();
|
||||
//void toSignUp();
|
||||
|
||||
QString fullNumber() const;
|
||||
void stopCheck();
|
||||
|
||||
void showPhoneError(base::lambda<QString()> textFactory);
|
||||
void hidePhoneError();
|
||||
void showSignup();
|
||||
//void showSignup();
|
||||
|
||||
bool _changed = false;
|
||||
|
||||
object_ptr<CountryInput> _country;
|
||||
object_ptr<Ui::CountryCodeInput> _code;
|
||||
object_ptr<Ui::PhonePartInput> _phone;
|
||||
bool _termsAccepted = false;
|
||||
|
||||
object_ptr<Ui::FadeWrap<Ui::FlatLabel>> _signup = { nullptr };
|
||||
|
||||
|
||||
@@ -41,6 +41,67 @@ namespace {
|
||||
|
||||
constexpr str_const kDefaultCountry = "US";
|
||||
|
||||
class TermsBox : public BoxContent {
|
||||
public:
|
||||
TermsBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
base::lambda<QString()> button);
|
||||
|
||||
rpl::producer<> agreeClicks() const;
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
QString _text;
|
||||
base::lambda<QString()> _button;
|
||||
rpl::event_stream<> _agreeClicks;
|
||||
|
||||
};
|
||||
|
||||
TermsBox::TermsBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
base::lambda<QString()> button)
|
||||
: _text(text)
|
||||
, _button(button) {
|
||||
}
|
||||
|
||||
rpl::producer<> TermsBox::agreeClicks() const {
|
||||
return _agreeClicks.events();
|
||||
}
|
||||
|
||||
void TermsBox::prepare() {
|
||||
setTitle(langFactory(lng_terms_header));
|
||||
addButton(_button, [=] {})->clicks(
|
||||
) | rpl::start_to_stream(_agreeClicks, lifetime());
|
||||
|
||||
const auto content = Ui::CreateChild<Ui::PaddingWrap<Ui::FlatLabel>>(
|
||||
this,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
this,
|
||||
_text,
|
||||
Ui::FlatLabel::InitType::Rich,
|
||||
st::introTermsContent),
|
||||
st::introTermsPadding);
|
||||
content->resizeToWidth(st::boxWideWidth);
|
||||
content->heightValue(
|
||||
) | rpl::start_with_next([=](int height) {
|
||||
setDimensions(st::boxWideWidth, height);
|
||||
}, content->lifetime());
|
||||
}
|
||||
|
||||
void TermsBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
_agreeClicks.fire({});
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Widget::Widget(QWidget *parent) : RpWidget(parent)
|
||||
@@ -122,7 +183,9 @@ void Widget::createLanguageLink() {
|
||||
_changeLanguage->entity()->setClickedCallback([=] {
|
||||
Lang::CurrentCloudManager().switchToLanguage(languageId);
|
||||
});
|
||||
_changeLanguage->toggle(!_resetAccount, anim::type::normal);
|
||||
_changeLanguage->toggle(
|
||||
!_resetAccount && !_terms,
|
||||
anim::type::normal);
|
||||
updateControlsGeometry();
|
||||
};
|
||||
|
||||
@@ -158,6 +221,8 @@ void Widget::onCheckUpdateStatus() {
|
||||
if (!_a_show.animating()) {
|
||||
_update->setVisible(true);
|
||||
}
|
||||
const auto stepHasCover = getStep()->hasCover();
|
||||
_update->toggle(!stepHasCover, anim::type::instant);
|
||||
_update->entity()->setClickedCallback([] {
|
||||
Core::checkReadyUpdate();
|
||||
App::restart();
|
||||
@@ -207,14 +272,36 @@ void Widget::historyMove(Direction direction) {
|
||||
|
||||
auto stepHasCover = getStep()->hasCover();
|
||||
_settings->toggle(!stepHasCover, anim::type::normal);
|
||||
if (_update) _update->toggle(!stepHasCover, anim::type::normal);
|
||||
if (_changeLanguage) _changeLanguage->toggle(!_resetAccount, anim::type::normal);
|
||||
if (_update) {
|
||||
_update->toggle(!stepHasCover, anim::type::normal);
|
||||
}
|
||||
_next->setText([this] { return getStep()->nextButtonText(); });
|
||||
if (_resetAccount) _resetAccount->hide(anim::type::normal);
|
||||
if (_resetAccount) {
|
||||
hideAndDestroy(std::exchange(_resetAccount, { nullptr }));
|
||||
}
|
||||
if (_terms) {
|
||||
hideAndDestroy(std::exchange(_terms, { nullptr }));
|
||||
}
|
||||
if (_changeLanguage) {
|
||||
_changeLanguage->toggle(
|
||||
!_resetAccount && !_terms,
|
||||
anim::type::normal);
|
||||
}
|
||||
getStep()->showAnimated(direction);
|
||||
fixOrder();
|
||||
}
|
||||
|
||||
void Widget::hideAndDestroy(object_ptr<Ui::FadeWrap<Ui::RpWidget>> widget) {
|
||||
const auto weak = make_weak(widget.data());
|
||||
widget->hide(anim::type::normal);
|
||||
widget->shownValue(
|
||||
) | rpl::start_with_next([=](bool shown) {
|
||||
if (!shown && weak) {
|
||||
weak->deleteLater();
|
||||
}
|
||||
}, widget->lifetime());
|
||||
}
|
||||
|
||||
void Widget::fixOrder() {
|
||||
_next->raise();
|
||||
if (_update) _update->raise();
|
||||
@@ -238,30 +325,74 @@ void Widget::moveToStep(Step *step, Direction direction) {
|
||||
void Widget::appendStep(Step *step) {
|
||||
_stepHistory.push_back(step);
|
||||
step->setGeometry(calculateStepRect());
|
||||
step->setGoCallback([this](Step *step, Direction direction) {
|
||||
step->setGoCallback([=](Step *step, Direction direction) {
|
||||
if (direction == Direction::Back) {
|
||||
historyMove(direction);
|
||||
} else {
|
||||
moveToStep(step, direction);
|
||||
}
|
||||
});
|
||||
step->setShowResetCallback([this] {
|
||||
step->setShowResetCallback([=] {
|
||||
showResetButton();
|
||||
});
|
||||
step->setToggleTermsCallback([=](QString countryCode) {
|
||||
toggleTerms(countryCode);
|
||||
});
|
||||
step->setAcceptTermsCallback([=](
|
||||
QString countryCode,
|
||||
base::lambda<void()> callback) {
|
||||
acceptTerms(countryCode, callback);
|
||||
});
|
||||
}
|
||||
|
||||
void Widget::showResetButton() {
|
||||
if (!_resetAccount) {
|
||||
auto entity = object_ptr<Ui::RoundButton>(this, langFactory(lng_signin_reset_account), st::introResetButton);
|
||||
_resetAccount.create(
|
||||
this,
|
||||
std::move(entity));
|
||||
_resetAccount.create(this, std::move(entity));
|
||||
_resetAccount->hide(anim::type::instant);
|
||||
_resetAccount->entity()->setClickedCallback([this] { resetAccount(); });
|
||||
updateControlsGeometry();
|
||||
}
|
||||
_resetAccount->show(anim::type::normal);
|
||||
if (_changeLanguage) _changeLanguage->hide(anim::type::normal);
|
||||
if (_changeLanguage) {
|
||||
_changeLanguage->hide(anim::type::normal);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::toggleTerms(const QString &countryCode) {
|
||||
_termsCountryCode = countryCode;
|
||||
if (countryCode.isEmpty()) {
|
||||
if (_terms) hideAndDestroy(std::exchange(_terms, { nullptr }));
|
||||
} else {
|
||||
if (!_terms) {
|
||||
auto entity = object_ptr<Ui::FlatLabel>(
|
||||
this,
|
||||
lng_terms_signup(
|
||||
lt_link,
|
||||
textcmdLink(1, lang(lng_terms_signup_link))),
|
||||
Ui::FlatLabel::InitType::Rich,
|
||||
st::introTermsLabel);
|
||||
_terms.create(this, std::move(entity));
|
||||
_terms->hide(anim::type::instant);
|
||||
_terms->entity()->setLink(
|
||||
1,
|
||||
std::make_shared<LambdaClickHandler>([=] { showTerms(); }));
|
||||
updateControlsGeometry();
|
||||
}
|
||||
_terms->toggle(!_termsCountryCode.isEmpty(), anim::type::normal);
|
||||
}
|
||||
if (_changeLanguage) {
|
||||
_changeLanguage->toggle(
|
||||
!_terms && !_resetAccount,
|
||||
anim::type::normal);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::acceptTerms(
|
||||
const QString &countryCode,
|
||||
base::lambda<void()> callback) {
|
||||
_termsCountryCode = countryCode;
|
||||
showTerms(callback);
|
||||
}
|
||||
|
||||
void Widget::resetAccount() {
|
||||
@@ -306,7 +437,10 @@ void Widget::resetAccount() {
|
||||
void Widget::getNearestDC() {
|
||||
request(MTPhelp_GetNearestDc()).done([this](const MTPNearestDc &result) {
|
||||
auto &nearest = result.c_nearestDc();
|
||||
DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(qs(nearest.vcountry)).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v));
|
||||
DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3"
|
||||
).arg(qs(nearest.vcountry)
|
||||
).arg(nearest.vnearest_dc.v
|
||||
).arg(nearest.vthis_dc.v));
|
||||
Messenger::Instance().suggestMainDcId(nearest.vnearest_dc.v);
|
||||
auto nearestCountry = qs(nearest.vcountry);
|
||||
if (getData()->country != nearestCountry) {
|
||||
@@ -316,6 +450,56 @@ void Widget::getNearestDC() {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Widget::showTerms(base::lambda<void()> callback) {
|
||||
if (_termsCountryCode.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const auto showLastTerms = [=] {
|
||||
const auto box = Ui::show(Box<TermsBox>(
|
||||
_termsLastText,
|
||||
langFactory(callback ? lng_terms_agree : lng_box_ok)));
|
||||
box->agreeClicks(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
if (box) {
|
||||
box->closeBox();
|
||||
}
|
||||
}, box->lifetime());
|
||||
};
|
||||
const auto langPack = Lang::Current().id();
|
||||
const auto code = _termsCountryCode;
|
||||
if (_termsLastCountryCode == code && _termsLastLangPack == langPack) {
|
||||
showLastTerms();
|
||||
return;
|
||||
}
|
||||
|
||||
request(MTPhelp_GetTermsOfService(
|
||||
MTP_string(code)
|
||||
)).done([=](const MTPhelp_TermsOfService &result) {
|
||||
const auto text = qs(result.c_help_termsOfService().vtext);
|
||||
const auto match = QRegularExpression("\\[([^\\]]+)\\]").match(text);
|
||||
const auto linked = [&] {
|
||||
if (!match.hasMatch()) {
|
||||
return text;
|
||||
}
|
||||
const auto from = match.capturedStart(0);
|
||||
const auto till = from + match.capturedLength(0);
|
||||
return text.mid(0, from)
|
||||
+ textcmdLink(
|
||||
"http://telegram.org/privacy",
|
||||
text.mid(from + 1, till - from - 2))
|
||||
+ text.mid(till);
|
||||
}();
|
||||
_termsLastCountryCode = code;
|
||||
_termsLastLangPack = langPack;
|
||||
_termsLastText = linked;
|
||||
|
||||
showLastTerms();
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Widget::showControls() {
|
||||
getStep()->show();
|
||||
_next->show();
|
||||
@@ -323,8 +507,14 @@ void Widget::showControls() {
|
||||
_connecting->setForceHidden(false);
|
||||
auto hasCover = getStep()->hasCover();
|
||||
_settings->toggle(!hasCover, anim::type::instant);
|
||||
if (_update) _update->toggle(!hasCover, anim::type::instant);
|
||||
if (_changeLanguage) _changeLanguage->toggle(!_resetAccount, anim::type::instant);
|
||||
if (_update) {
|
||||
_update->toggle(!hasCover, anim::type::instant);
|
||||
}
|
||||
if (_changeLanguage) {
|
||||
_changeLanguage->toggle(
|
||||
!_resetAccount && !_terms,
|
||||
anim::type::instant);
|
||||
}
|
||||
_back->toggle(getStep()->hasBack(), anim::type::instant);
|
||||
}
|
||||
|
||||
@@ -432,6 +622,9 @@ void Widget::updateControlsGeometry() {
|
||||
if (_resetAccount) {
|
||||
_resetAccount->moveToLeft((width() - _resetAccount->width()) / 2, height() - st::introResetBottom - _resetAccount->height());
|
||||
}
|
||||
if (_terms) {
|
||||
_terms->moveToLeft((width() - _terms->width()) / 2, height() - st::introTermsBottom - _terms->height());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -831,6 +1024,17 @@ void Widget::Step::setShowResetCallback(base::lambda<void()> callback) {
|
||||
_showResetCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void Widget::Step::setToggleTermsCallback(
|
||||
base::lambda<void(QString countryCode)> callback) {
|
||||
_toggleTermsCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void Widget::Step::setAcceptTermsCallback(base::lambda<void(
|
||||
QString countryCode,
|
||||
base::lambda<void()> callback)> callback) {
|
||||
_acceptTermsCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void Widget::Step::showFast() {
|
||||
show();
|
||||
showFinished();
|
||||
|
||||
@@ -94,8 +94,14 @@ public:
|
||||
setFocus();
|
||||
}
|
||||
|
||||
void setGoCallback(base::lambda<void(Step *step, Direction direction)> callback);
|
||||
void setGoCallback(
|
||||
base::lambda<void(Step *step, Direction direction)> callback);
|
||||
void setShowResetCallback(base::lambda<void()> callback);
|
||||
void setToggleTermsCallback(
|
||||
base::lambda<void(QString countryCode)> callback);
|
||||
void setAcceptTermsCallback(base::lambda<void(
|
||||
QString countryCode,
|
||||
base::lambda<void()> callback)> callback);
|
||||
|
||||
void prepareShowAnimated(Step *after);
|
||||
void showAnimated(Direction direction);
|
||||
@@ -153,6 +159,16 @@ public:
|
||||
void showResetButton() {
|
||||
if (_showResetCallback) _showResetCallback();
|
||||
}
|
||||
void toggleTerms(const QString &countryCode) {
|
||||
if (_toggleTermsCallback) _toggleTermsCallback(countryCode);
|
||||
}
|
||||
void acceptTerms(
|
||||
const QString &countryCode,
|
||||
base::lambda<void()> callback) {
|
||||
if (_acceptTermsCallback) {
|
||||
_acceptTermsCallback(countryCode, callback);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct CoverAnimation {
|
||||
@@ -187,6 +203,10 @@ public:
|
||||
bool _hasCover = false;
|
||||
base::lambda<void(Step *step, Direction direction)> _goCallback;
|
||||
base::lambda<void()> _showResetCallback;
|
||||
base::lambda<void(QString countryCode)> _toggleTermsCallback;
|
||||
base::lambda<void(
|
||||
QString countryCode,
|
||||
base::lambda<void()> callback)> _acceptTermsCallback;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _title;
|
||||
base::lambda<QString()> _titleTextFactory;
|
||||
@@ -224,6 +244,12 @@ private:
|
||||
void showResetButton();
|
||||
void resetAccount();
|
||||
|
||||
void toggleTerms(const QString &countryCode);
|
||||
void acceptTerms(
|
||||
const QString &countryCode,
|
||||
base::lambda<void()> callback);
|
||||
void hideAndDestroy(object_ptr<Ui::FadeWrap<Ui::RpWidget>> widget);
|
||||
|
||||
Step *getStep(int skip = 0) {
|
||||
Assert(_stepHistory.size() + skip > 0);
|
||||
return _stepHistory.at(_stepHistory.size() - skip - 1);
|
||||
@@ -233,6 +259,7 @@ private:
|
||||
void appendStep(Step *step);
|
||||
|
||||
void getNearestDC();
|
||||
void showTerms(base::lambda<void()> callback = nullptr);
|
||||
|
||||
Animation _a_show;
|
||||
bool _showBack = false;
|
||||
@@ -253,6 +280,11 @@ private:
|
||||
object_ptr<Ui::RoundButton> _next;
|
||||
object_ptr<Ui::FadeWrap<Ui::LinkButton>> _changeLanguage = { nullptr };
|
||||
object_ptr<Ui::FadeWrap<Ui::RoundButton>> _resetAccount = { nullptr };
|
||||
object_ptr<Ui::FadeWrap<Ui::FlatLabel>> _terms = { nullptr };
|
||||
QString _termsCountryCode;
|
||||
QString _termsLastCountryCode;
|
||||
QString _termsLastLangPack;
|
||||
QString _termsLastText;
|
||||
|
||||
base::unique_qptr<Window::ConnectingWidget> _connecting;
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ QMap<QString, ChoosePluralMethod> GeneratePluralRulesMap() {
|
||||
// result.insert(qsl("nl"), ChoosePluralEn);
|
||||
result.insert(qsl("pt"), ChoosePluralPt);
|
||||
result.insert(qsl("ru"), ChoosePluralRu);
|
||||
result.insert(qsl("uk"), ChoosePluralRu);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,6 @@ MainWidget::MainWidget(
|
||||
connect(&_byPtsTimer, SIGNAL(timeout()), this, SLOT(onGetDifferenceTimeByPts()));
|
||||
connect(&_byMinChannelTimer, SIGNAL(timeout()), this, SLOT(getDifference()));
|
||||
connect(&_failDifferenceTimer, SIGNAL(timeout()), this, SLOT(onGetDifferenceTimeAfterFail()));
|
||||
connect(&updateNotifySettingTimer, SIGNAL(timeout()), this, SLOT(onUpdateNotifySettings()));
|
||||
subscribe(Media::Player::Updated(), [this](const AudioMsgId &audioId) {
|
||||
if (audioId.type() != AudioMsgId::Type::Video) {
|
||||
handleAudioUpdate(audioId);
|
||||
@@ -268,7 +267,6 @@ MainWidget::MainWidget(
|
||||
|
||||
QCoreApplication::instance()->installEventFilter(this);
|
||||
|
||||
connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted()));
|
||||
connect(&_viewsIncrementTimer, SIGNAL(timeout()), this, SLOT(onViewsIncrement()));
|
||||
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
@@ -715,20 +713,9 @@ void MainWidget::finishForwarding(not_null<History*> history) {
|
||||
dialogsToUp();
|
||||
}
|
||||
|
||||
void MainWidget::updateMutedIn(TimeMs delay) {
|
||||
accumulate_min(delay, 24 * 3600 * 1000LL);
|
||||
if (!_updateMutedTimer.isActive()
|
||||
|| _updateMutedTimer.remainingTime() > delay) {
|
||||
_updateMutedTimer.start(delay);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::onUpdateMuted() {
|
||||
App::updateMuted();
|
||||
}
|
||||
|
||||
bool MainWidget::onSendPaths(const PeerId &peerId) {
|
||||
Expects(peerId != 0);
|
||||
|
||||
auto peer = App::peer(peerId);
|
||||
if (!peer->canWrite()) {
|
||||
Ui::show(Box<InformBox>(lang(lng_forward_send_files_cant)));
|
||||
@@ -1262,7 +1249,10 @@ void MainWidget::sendMessage(const MessageToSend &message) {
|
||||
saveRecentHashtags(textWithTags.text);
|
||||
|
||||
auto sending = TextWithEntities();
|
||||
auto left = TextWithEntities { textWithTags.text, ConvertTextTagsToEntities(textWithTags.tags) };
|
||||
auto left = TextWithEntities {
|
||||
textWithTags.text,
|
||||
ConvertTextTagsToEntities(textWithTags.tags)
|
||||
};
|
||||
auto prepareFlags = Ui::ItemTextOptions(history, App::self()).flags;
|
||||
TextUtilities::PrepareForSending(left, prepareFlags);
|
||||
|
||||
@@ -1296,7 +1286,8 @@ void MainWidget::sendMessage(const MessageToSend &message) {
|
||||
flags |= MTPDmessage::Flag::f_media;
|
||||
}
|
||||
bool channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
bool silentPost = channelPost && peer->notifySilentPosts();
|
||||
bool silentPost = channelPost
|
||||
&& Auth().data().notifySilentPosts(peer);
|
||||
if (channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
@@ -1319,7 +1310,9 @@ void MainWidget::sendMessage(const MessageToSend &message) {
|
||||
history->clearCloudDraft();
|
||||
}
|
||||
auto messageFromId = channelPost ? 0 : Auth().userId();
|
||||
auto messagePostAuthor = channelPost ? (Auth().user()->firstName + ' ' + Auth().user()->lastName) : QString();
|
||||
auto messagePostAuthor = channelPost
|
||||
? App::peerName(Auth().user())
|
||||
: QString();
|
||||
lastMessage = history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
@@ -3307,22 +3300,6 @@ void MainWidget::searchInChat(Dialogs::Key chat) {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::onUpdateNotifySettings() {
|
||||
if (this != App::main()) return;
|
||||
|
||||
while (!updateNotifySettingPeers.empty()) {
|
||||
auto peer = *updateNotifySettingPeers.begin();
|
||||
updateNotifySettingPeers.erase(updateNotifySettingPeers.begin());
|
||||
MTP::send(
|
||||
MTPaccount_UpdateNotifySettings(
|
||||
MTP_inputNotifyPeer(peer->input),
|
||||
peer->notifySerialize()),
|
||||
RPCResponseHandler(),
|
||||
0,
|
||||
updateNotifySettingPeers.empty() ? 0 : 10);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::feedUpdateVector(
|
||||
const MTPVector<MTPUpdate> &updates,
|
||||
bool skipMessageIds) {
|
||||
@@ -3996,62 +3973,6 @@ void MainWidget::startWithSelf(const MTPUserFull &result) {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::applyNotifySetting(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings,
|
||||
History *history) {
|
||||
if (notifyPeer.type() != mtpc_notifyPeer) {
|
||||
// Ignore those for now, they were not ever used.
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &data = notifyPeer.c_notifyPeer();
|
||||
const auto peer = App::peerLoaded(peerFromMTP(data.vpeer));
|
||||
if (!peer || !peer->notifyChange(settings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateNotifySettingsLocal(peer, history);
|
||||
}
|
||||
|
||||
void MainWidget::updateNotifySettings(
|
||||
not_null<PeerData*> peer,
|
||||
Data::NotifySettings::MuteChange mute,
|
||||
Data::NotifySettings::SilentPostsChange silent,
|
||||
int muteForSeconds) {
|
||||
if (peer->notifyChange(mute, silent, muteForSeconds)) {
|
||||
updateNotifySettingsLocal(peer);
|
||||
updateNotifySettingPeers.insert(peer);
|
||||
updateNotifySettingTimer.start(NotifySettingSaveTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::updateNotifySettingsLocal(
|
||||
not_null<PeerData*> peer,
|
||||
History *history) {
|
||||
if (!history) {
|
||||
history = App::historyLoaded(peer->id);
|
||||
}
|
||||
|
||||
const auto muteFinishesIn = peer->notifyMuteFinishesIn();
|
||||
const auto muted = (muteFinishesIn > 0);
|
||||
if (history && history->changeMute(muted)) {
|
||||
// Notification already sent.
|
||||
} else {
|
||||
Notify::peerUpdatedDelayed(
|
||||
peer,
|
||||
Notify::PeerUpdate::Flag::NotificationsEnabled);
|
||||
}
|
||||
if (muted) {
|
||||
App::regMuted(peer, muteFinishesIn);
|
||||
if (history) {
|
||||
Auth().notifications().clearFromHistory(history);
|
||||
}
|
||||
} else {
|
||||
App::unregMuted(peer);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::incrementSticker(DocumentData *sticker) {
|
||||
if (!sticker || !sticker->sticker()) return;
|
||||
if (sticker->sticker()->set.type() == mtpc_inputStickerSetEmpty) return;
|
||||
@@ -4940,7 +4861,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||
|
||||
case mtpc_updateNotifySettings: {
|
||||
auto &d = update.c_updateNotifySettings();
|
||||
applyNotifySetting(d.vpeer, d.vnotify_settings);
|
||||
Auth().data().applyNotifySetting(d.vpeer, d.vnotify_settings);
|
||||
} break;
|
||||
|
||||
case mtpc_updateDcOptions: {
|
||||
|
||||
@@ -93,17 +93,6 @@ public:
|
||||
void stickersBox(const MTPInputStickerSet &set);
|
||||
|
||||
bool started();
|
||||
void applyNotifySetting(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings,
|
||||
History *history = 0);
|
||||
|
||||
void updateNotifySettings(
|
||||
not_null<PeerData*> peer,
|
||||
Data::NotifySettings::MuteChange mute,
|
||||
Data::NotifySettings::SilentPostsChange silent
|
||||
= Data::NotifySettings::SilentPostsChange::Ignore,
|
||||
int muteForSeconds = 86400 * 365);
|
||||
|
||||
void incrementSticker(DocumentData *sticker);
|
||||
|
||||
@@ -275,8 +264,6 @@ public:
|
||||
void cancelForwarding(not_null<History*> history);
|
||||
void finishForwarding(not_null<History*> history);
|
||||
|
||||
void updateMutedIn(TimeMs delay);
|
||||
|
||||
// Does offerPeer or showPeerHistory.
|
||||
void choosePeer(PeerId peerId, MsgId showAtMsgId);
|
||||
void clearBotStartToken(PeerData *peer);
|
||||
@@ -355,14 +342,10 @@ public slots:
|
||||
void updateOnline(bool gotOtherOffline = false);
|
||||
void checkIdleFinish();
|
||||
|
||||
void onUpdateNotifySettings();
|
||||
|
||||
void onCacheBackground();
|
||||
|
||||
void onInviteImport();
|
||||
|
||||
void onUpdateMuted();
|
||||
|
||||
void onViewsIncrement();
|
||||
|
||||
protected:
|
||||
@@ -535,15 +518,9 @@ private:
|
||||
void ensureFirstColumnResizeAreaCreated();
|
||||
void ensureThirdColumnResizeAreaCreated();
|
||||
|
||||
void updateNotifySettingsLocal(
|
||||
not_null<PeerData*> peer,
|
||||
History *history = nullptr);
|
||||
|
||||
not_null<Window::Controller*> _controller;
|
||||
bool _started = false;
|
||||
|
||||
SingleTimer _updateMutedTimer;
|
||||
|
||||
QString _inviteHash;
|
||||
|
||||
Animation _a_show;
|
||||
@@ -607,9 +584,6 @@ private:
|
||||
TimeMs _lastSetOnline = 0;
|
||||
bool _isIdle = false;
|
||||
|
||||
base::flat_set<not_null<PeerData*>> updateNotifySettingPeers;
|
||||
SingleTimer updateNotifySettingTimer;
|
||||
|
||||
int32 _failDifferenceTimeout = 1; // growing timeout for getDifference calls, if it fails
|
||||
typedef QMap<ChannelData*, int32> ChannelFailDifferenceTimeout;
|
||||
ChannelFailDifferenceTimeout _channelFailDifferenceTimeout; // growing timeout for getChannelDifference calls, if it fails
|
||||
|
||||
@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_translator.h"
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
#include "lang/lang_hardcoded.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "observer_peer.h"
|
||||
#include "storage/file_upload.h"
|
||||
#include "mainwidget.h"
|
||||
@@ -462,7 +463,12 @@ void Messenger::startMtp() {
|
||||
_private->storedAuthSession.reset();
|
||||
}
|
||||
|
||||
_langCloudManager = std::make_unique<Lang::CloudManager>(langpack(), mtp());
|
||||
_langCloudManager = std::make_unique<Lang::CloudManager>(
|
||||
langpack(),
|
||||
mtp());
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
Core::UpdateChecker().setMtproto(mtp());
|
||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
}
|
||||
|
||||
void Messenger::destroyMtpKeys(MTP::AuthKeysList &&keys) {
|
||||
|
||||
@@ -1144,6 +1144,9 @@ void ConnectionPrivate::connectToServer(bool afterConfig) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(("Connection Info: Connecting to %1 with %2 test connections."
|
||||
).arg(_shiftedDcId
|
||||
).arg(_testConnections.size()));
|
||||
|
||||
if (!_startedConnectingAt) {
|
||||
_startedConnectingAt = getms(true);
|
||||
|
||||
@@ -71,7 +71,6 @@ void HttpConnection::connectToServer(
|
||||
const bytes::vector &protocolSecret,
|
||||
int16 protocolDcId) {
|
||||
_address = address;
|
||||
TCP_LOG(("HTTP Info: address is %1").arg(url().toDisplayString()));
|
||||
connect(
|
||||
&_manager,
|
||||
&QNetworkAccessManager::finished,
|
||||
@@ -80,8 +79,10 @@ void HttpConnection::connectToServer(
|
||||
|
||||
mtpBuffer buffer(preparePQFake(_checkNonce));
|
||||
|
||||
DEBUG_LOG(("Connection Info: "
|
||||
"sending fake req_pq through HTTP transport to '%1'").arg(address));
|
||||
DEBUG_LOG(("HTTP Info: "
|
||||
"dc:%1 - Sending fake req_pq to '%2'"
|
||||
).arg(protocolDcId
|
||||
).arg(url().toDisplayString()));
|
||||
|
||||
_pingTime = getms();
|
||||
sendData(buffer);
|
||||
|
||||
@@ -70,6 +70,12 @@ void ResolvingConnection::setChild(ConnectionPointer &&child) {
|
||||
&AbstractConnection::disconnected,
|
||||
this,
|
||||
&ResolvingConnection::handleDisconnected);
|
||||
DEBUG_LOG(("Resolving Info: dc:%1 proxy '%2' got new child '%3'"
|
||||
).arg(_protocolDcId
|
||||
).arg(_proxy.host + ':' + QString::number(_proxy.port)
|
||||
).arg((_ipIndex >= 0 && _ipIndex < _proxy.resolvedIPs.size())
|
||||
? _proxy.resolvedIPs[_ipIndex]
|
||||
: _proxy.host));
|
||||
if (_protocolDcId) {
|
||||
_child->connectToServer(
|
||||
_address,
|
||||
@@ -213,6 +219,12 @@ void ResolvingConnection::connectToServer(
|
||||
_port = port;
|
||||
_protocolSecret = protocolSecret;
|
||||
_protocolDcId = protocolDcId;
|
||||
DEBUG_LOG(("Resolving Info: dc:%1 proxy '%2' connects a child '%3'"
|
||||
).arg(_protocolDcId
|
||||
).arg(_proxy.host +':' + QString::number(_proxy.port)
|
||||
).arg((_ipIndex >= 0 && _ipIndex < _proxy.resolvedIPs.size())
|
||||
? _proxy.resolvedIPs[_ipIndex]
|
||||
: _proxy.host));
|
||||
return _child->connectToServer(
|
||||
address,
|
||||
port,
|
||||
|
||||
@@ -16,9 +16,8 @@ namespace MTP {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMinReceiveTimeout = TimeMs(2000);
|
||||
constexpr auto kMaxReceiveTimeout = TimeMs(8000);
|
||||
constexpr auto kPacketSizeMax = 64 * 1024 * 1024U;
|
||||
constexpr auto kFullConnectionTimeout = 8 * TimeMs(1000);
|
||||
|
||||
uint32 CountTcpPacketSize(const char *packet) { // must have at least 4 bytes readable
|
||||
uint32 result = (packet[0] > 0) ? packet[0] : 0;
|
||||
@@ -38,12 +37,9 @@ const auto QTcpSocket_error = ErrorSignal(&QAbstractSocket::error);
|
||||
TcpConnection::TcpConnection(QThread *thread, const ProxyData &proxy)
|
||||
: AbstractConnection(thread, proxy)
|
||||
, _currentPosition(reinterpret_cast<char*>(_shortBuffer))
|
||||
, _checkNonce(rand_value<MTPint128>())
|
||||
, _timeout(kMinReceiveTimeout)
|
||||
, _timeoutTimer(thread, [=] { handleTimeout(); }) {
|
||||
, _checkNonce(rand_value<MTPint128>()) {
|
||||
_socket.moveToThread(thread);
|
||||
_socket.setProxy(ToNetworkProxy(proxy));
|
||||
connect(&_socket, QTcpSocket_error, this, &TcpConnection::socketError);
|
||||
connect(
|
||||
&_socket,
|
||||
&QTcpSocket::connected,
|
||||
@@ -54,6 +50,16 @@ TcpConnection::TcpConnection(QThread *thread, const ProxyData &proxy)
|
||||
&QTcpSocket::disconnected,
|
||||
this,
|
||||
&TcpConnection::socketDisconnected);
|
||||
connect(
|
||||
&_socket,
|
||||
&QTcpSocket::readyRead,
|
||||
this,
|
||||
&TcpConnection::socketRead);
|
||||
connect(
|
||||
&_socket,
|
||||
QTcpSocket_error,
|
||||
this,
|
||||
&TcpConnection::socketError);
|
||||
}
|
||||
|
||||
ConnectionPointer TcpConnection::clone(const ProxyData &proxy) {
|
||||
@@ -228,43 +234,20 @@ void TcpConnection::handleError(QAbstractSocket::SocketError e, QTcpSocket &sock
|
||||
}
|
||||
|
||||
void TcpConnection::socketConnected() {
|
||||
if (_status == Status::Waiting) {
|
||||
mtpBuffer buffer(preparePQFake(_checkNonce));
|
||||
Expects(_status == Status::Waiting);
|
||||
|
||||
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP transport to %1").arg(_address));
|
||||
auto buffer = preparePQFake(_checkNonce);
|
||||
|
||||
if (_timeout < 0) _timeout = -_timeout;
|
||||
_timeoutTimer.callOnce(_timeout);
|
||||
DEBUG_LOG(("TCP Info: "
|
||||
"dc:%1 - Sending fake req_pq to '%2'"
|
||||
).arg(_protocolDcId
|
||||
).arg(_address + ':' + QString::number(_port)));
|
||||
|
||||
_pingTime = getms();
|
||||
sendData(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void TcpConnection::handleTimeout() {
|
||||
if (_status == Status::Waiting) {
|
||||
if (_timeout < kMaxReceiveTimeout) {
|
||||
_timeout *= 2;
|
||||
}
|
||||
_timeout = -_timeout;
|
||||
|
||||
QAbstractSocket::SocketState state = _socket.state();
|
||||
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
|
||||
_socket.disconnectFromHost();
|
||||
} else if (state != QAbstractSocket::ClosingState) {
|
||||
_socket.connectToHost(_address, _port);
|
||||
}
|
||||
}
|
||||
_pingTime = getms();
|
||||
sendData(buffer);
|
||||
}
|
||||
|
||||
void TcpConnection::socketDisconnected() {
|
||||
if (_timeout < 0) {
|
||||
_timeout = -_timeout;
|
||||
if (_status == Status::Waiting) {
|
||||
_socket.connectToHost(_address, _port);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (_status == Status::Waiting || _status == Status::Ready) {
|
||||
emit disconnected();
|
||||
}
|
||||
@@ -377,7 +360,10 @@ void TcpConnection::disconnectFromServer() {
|
||||
if (_status == Status::Finished) return;
|
||||
_status = Status::Finished;
|
||||
|
||||
disconnect(&_socket, &QTcpSocket::connected, nullptr, nullptr);
|
||||
disconnect(&_socket, &QTcpSocket::disconnected, nullptr, nullptr);
|
||||
disconnect(&_socket, &QTcpSocket::readyRead, nullptr, nullptr);
|
||||
disconnect(&_socket, QTcpSocket_error, nullptr, nullptr);
|
||||
_socket.close();
|
||||
}
|
||||
|
||||
@@ -386,18 +372,32 @@ void TcpConnection::connectToServer(
|
||||
int port,
|
||||
const bytes::vector &protocolSecret,
|
||||
int16 protocolDcId) {
|
||||
Expects(_address.isEmpty());
|
||||
Expects(_port == 0);
|
||||
Expects(_protocolSecret.empty());
|
||||
Expects(_protocolDcId == 0);
|
||||
|
||||
if (_proxy.type == ProxyData::Type::Mtproto) {
|
||||
_address = _proxy.host;
|
||||
_port = _proxy.port;
|
||||
_protocolSecret = ProtocolSecretFromPassword(_proxy.password);
|
||||
|
||||
DEBUG_LOG(("TCP Info: "
|
||||
"dc:%1 - Connecting to proxy '%2'"
|
||||
).arg(protocolDcId
|
||||
).arg(_address + ':' + QString::number(_port)));
|
||||
} else {
|
||||
_address = address;
|
||||
_port = port;
|
||||
_protocolSecret = protocolSecret;
|
||||
|
||||
DEBUG_LOG(("TCP Info: "
|
||||
"dc:%1 - Connecting to '%2'"
|
||||
).arg(protocolDcId
|
||||
).arg(_address + ':' + QString::number(_port)));
|
||||
}
|
||||
_protocolDcId = protocolDcId;
|
||||
|
||||
connect(&_socket, &QTcpSocket::readyRead, this, [=] { socketRead(); });
|
||||
_socket.connectToHost(_address, _port);
|
||||
}
|
||||
|
||||
@@ -406,26 +406,30 @@ TimeMs TcpConnection::pingTime() const {
|
||||
}
|
||||
|
||||
TimeMs TcpConnection::fullConnectTimeout() const {
|
||||
return kMaxReceiveTimeout;
|
||||
return kFullConnectionTimeout;
|
||||
}
|
||||
|
||||
void TcpConnection::socketPacket(const char *packet, uint32 length) {
|
||||
if (_status == Status::Finished) return;
|
||||
|
||||
mtpBuffer data = handleResponse(packet, length);
|
||||
const auto data = handleResponse(packet, length);
|
||||
if (data.size() == 1) {
|
||||
emit error(data[0]);
|
||||
} else if (_status == Status::Ready) {
|
||||
_receivedQueue.push_back(data);
|
||||
emit receivedData();
|
||||
} else if (_status == Status::Waiting) {
|
||||
_timeoutTimer.cancel();
|
||||
try {
|
||||
auto res_pq = readPQFakeReply(data);
|
||||
const auto &res_pq_data(res_pq.c_resPQ());
|
||||
if (res_pq_data.vnonce == _checkNonce) {
|
||||
DEBUG_LOG(("Connection Info: TCP-transport to %1 chosen by pq-response").arg(_address));
|
||||
const auto res_pq = readPQFakeReply(data);
|
||||
const auto &data = res_pq.c_resPQ();
|
||||
if (data.vnonce == _checkNonce) {
|
||||
DEBUG_LOG(("Connection Info: Valid pq response by TCP."));
|
||||
_status = Status::Ready;
|
||||
disconnect(
|
||||
&_socket,
|
||||
&QTcpSocket::connected,
|
||||
nullptr,
|
||||
nullptr);
|
||||
_pingTime = (getms() - _pingTime);
|
||||
emit connected();
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ private:
|
||||
void socketConnected();
|
||||
void socketDisconnected();
|
||||
void socketError(QAbstractSocket::SocketError e);
|
||||
void handleTimeout();
|
||||
|
||||
mtpBuffer handleResponse(const char *packet, uint32 length);
|
||||
static void handleError(QAbstractSocket::SocketError e, QTcpSocket &sock);
|
||||
@@ -87,8 +86,6 @@ private:
|
||||
|
||||
QString _address;
|
||||
int32 _port = 0;
|
||||
int32 _timeout = 0;
|
||||
base::Timer _timeoutTimer;
|
||||
TimeMs _pingTime = 0;
|
||||
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@ void unpause();
|
||||
constexpr auto kDcShift = ShiftedDcId(10000);
|
||||
constexpr auto kConfigDcShift = 0x01;
|
||||
constexpr auto kLogoutDcShift = 0x02;
|
||||
constexpr auto kUpdaterDcShift = 0x03;
|
||||
constexpr auto kMaxMediaDcCount = 0x10;
|
||||
constexpr auto kBaseDownloadDcShift = 0x10;
|
||||
constexpr auto kBaseUploadDcShift = 0x20;
|
||||
@@ -72,6 +73,11 @@ constexpr ShiftedDcId logoutDcId(DcId dcId) {
|
||||
return shiftDcId(dcId, internal::kLogoutDcShift);
|
||||
}
|
||||
|
||||
// send(MTPupload_GetFile(), MTP::updaterDcId(dc)) - for autoupdater
|
||||
constexpr ShiftedDcId updaterDcId(DcId dcId) {
|
||||
return shiftDcId(dcId, internal::kUpdaterDcShift);
|
||||
}
|
||||
|
||||
constexpr auto kDownloadSessionsCount = 2;
|
||||
constexpr auto kUploadSessionsCount = 2;
|
||||
|
||||
|
||||
@@ -23,16 +23,16 @@ PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent)
|
||||
, _passcode(this, st::passcodeInput, langFactory(lng_passcode_ph))
|
||||
, _submit(this, langFactory(lng_passcode_submit), st::passcodeSubmit)
|
||||
, _logout(this, lang(lng_passcode_logout)) {
|
||||
connect(_passcode, SIGNAL(changed()), this, SLOT(onChanged()));
|
||||
connect(_passcode, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(_passcode, &Ui::MaskedInputField::changed, [=] { changed(); });
|
||||
connect(_passcode, &Ui::MaskedInputField::submitted, [=] { submit(); });
|
||||
|
||||
_submit->setClickedCallback([this] { onSubmit(); });
|
||||
_submit->setClickedCallback([=] { submit(); });
|
||||
_logout->setClickedCallback([] { App::wnd()->onLogout(); });
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
void PasscodeWidget::onSubmit() {
|
||||
void PasscodeWidget::submit() {
|
||||
if (_passcode->text().isEmpty()) {
|
||||
_passcode->showError();
|
||||
return;
|
||||
@@ -51,7 +51,7 @@ void PasscodeWidget::onSubmit() {
|
||||
} else {
|
||||
cSetPasscodeBadTries(cPasscodeBadTries() + 1);
|
||||
cSetPasscodeLastTry(getms(true));
|
||||
onError();
|
||||
error();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -67,20 +67,20 @@ void PasscodeWidget::onSubmit() {
|
||||
} else {
|
||||
cSetPasscodeBadTries(cPasscodeBadTries() + 1);
|
||||
cSetPasscodeLastTry(getms(true));
|
||||
onError();
|
||||
error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeWidget::onError() {
|
||||
void PasscodeWidget::error() {
|
||||
_error = lang(lng_passcode_wrong);
|
||||
_passcode->selectAll();
|
||||
_passcode->showError();
|
||||
update();
|
||||
}
|
||||
|
||||
void PasscodeWidget::onChanged() {
|
||||
void PasscodeWidget::changed() {
|
||||
if (!_error.isEmpty()) {
|
||||
_error = QString();
|
||||
update();
|
||||
|
||||
@@ -14,8 +14,6 @@ class RoundButton;
|
||||
} // namespace Ui
|
||||
|
||||
class PasscodeWidget : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PasscodeWidget(QWidget *parent);
|
||||
|
||||
@@ -27,13 +25,11 @@ protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
public slots:
|
||||
void onError();
|
||||
void onChanged();
|
||||
void onSubmit();
|
||||
|
||||
private:
|
||||
void animationCallback();
|
||||
void changed();
|
||||
void submit();
|
||||
void error();
|
||||
|
||||
void showAll();
|
||||
void hideAll();
|
||||
|
||||
@@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
|
||||
@@ -2560,7 +2560,7 @@ const QString &readAutoupdatePrefixRaw() {
|
||||
return AutoupdatePrefix(value);
|
||||
}
|
||||
}
|
||||
return AutoupdatePrefix("http://updates.tdesktop.com");
|
||||
return AutoupdatePrefix("https://updates.tdesktop.com");
|
||||
}
|
||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
|
||||
@@ -162,11 +162,12 @@ void CountryInput::leaveEventHook(QEvent *e) {
|
||||
|
||||
void CountryInput::onChooseCode(const QString &code) {
|
||||
Ui::hideLayer();
|
||||
_chosenIso = QString();
|
||||
if (code.length()) {
|
||||
CountriesByCode::const_iterator i = _countriesByCode.constFind(code);
|
||||
if (i != _countriesByCode.cend()) {
|
||||
const CountryInfo *info = *i;
|
||||
lastValidISO = info->iso2;
|
||||
_chosenIso = lastValidISO = info->iso2;
|
||||
setText(QString::fromUtf8(info->name));
|
||||
} else {
|
||||
setText(lang(lng_bad_country_code));
|
||||
@@ -183,8 +184,9 @@ bool CountryInput::onChooseCountry(const QString &iso) {
|
||||
CountriesByISO2::const_iterator i = _countriesByISO2.constFind(iso);
|
||||
const CountryInfo *info = (i == _countriesByISO2.cend()) ? 0 : (*i);
|
||||
|
||||
_chosenIso = QString();
|
||||
if (info) {
|
||||
lastValidISO = info->iso2;
|
||||
_chosenIso = lastValidISO = info->iso2;
|
||||
setText(QString::fromUtf8(info->name));
|
||||
emit codeChanged(info->code);
|
||||
update();
|
||||
@@ -206,7 +208,7 @@ void CountrySelectBox::prepare() {
|
||||
|
||||
_select->resizeToWidth(st::boxWidth);
|
||||
_select->setQueryChangedCallback([this](const QString &query) { onFilterUpdate(query); });
|
||||
_select->setSubmittedCallback([this](bool) { onSubmit(); });
|
||||
_select->setSubmittedCallback([this](Qt::KeyboardModifiers) { onSubmit(); });
|
||||
|
||||
_inner = setInnerWidget(object_ptr<Inner>(this), st::countriesScroll, _select->height());
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ class CountryInput : public TWidget {
|
||||
public:
|
||||
CountryInput(QWidget *parent, const style::InputField &st);
|
||||
|
||||
QString iso() const {
|
||||
return _chosenIso;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onChooseCode(const QString &code);
|
||||
bool onChooseCountry(const QString &country);
|
||||
@@ -43,6 +47,7 @@ private:
|
||||
const style::InputField &_st;
|
||||
bool _active = false;
|
||||
QString _text;
|
||||
QString _chosenIso;
|
||||
QPainterPath _placeholderPath;
|
||||
|
||||
};
|
||||
|
||||
@@ -918,8 +918,8 @@ QPoint FeedUserpicButton::countInnerPosition() const {
|
||||
SilentToggle::SilentToggle(QWidget *parent, not_null<ChannelData*> channel)
|
||||
: IconButton(parent, st::historySilentToggle)
|
||||
, _channel(channel)
|
||||
, _checked(_channel->notifySilentPosts()) {
|
||||
Expects(!_channel->notifySettingsUnknown());
|
||||
, _checked(Auth().data().notifySilentPosts(_channel)) {
|
||||
Expects(!Auth().data().notifySilentPostsUnknown(_channel));
|
||||
|
||||
if (_checked) {
|
||||
refreshIconOverrides();
|
||||
@@ -962,13 +962,10 @@ void SilentToggle::mouseReleaseEvent(QMouseEvent *e) {
|
||||
setChecked(!_checked);
|
||||
IconButton::mouseReleaseEvent(e);
|
||||
Ui::Tooltip::Show(0, this);
|
||||
const auto silentState = _checked
|
||||
? Data::NotifySettings::SilentPostsChange::Silent
|
||||
: Data::NotifySettings::SilentPostsChange::Notify;
|
||||
App::main()->updateNotifySettings(
|
||||
Auth().data().updateNotifySettings(
|
||||
_channel,
|
||||
Data::NotifySettings::MuteChange::Ignore,
|
||||
silentState);
|
||||
base::none,
|
||||
_checked);
|
||||
}
|
||||
|
||||
QString SilentToggle::tooltipText() const {
|
||||
|
||||
@@ -2991,18 +2991,13 @@ void Text::enumerateText(TextSelection selection, AppendPartCallback appendPartC
|
||||
uint16 blockFrom = (i == e) ? _text.size() : (*i)->from();
|
||||
int32 blockFlags = (i == e) ? 0 : (*i)->flags();
|
||||
|
||||
bool checkBlockFlags = (blockFrom >= selection.from) && (blockFrom <= selection.to);
|
||||
if (checkBlockFlags && blockFlags != flags) {
|
||||
flagsChangeCallback(flags, blockFlags);
|
||||
flags = blockFlags;
|
||||
}
|
||||
if (blockLnkIndex && !_links.at(blockLnkIndex - 1)) { // ignore empty links
|
||||
blockLnkIndex = 0;
|
||||
}
|
||||
if (blockLnkIndex != lnkIndex) {
|
||||
if (lnkIndex) {
|
||||
auto rangeFrom = qMax(selection.from, lnkFrom);
|
||||
auto rangeTo = qMin(blockFrom, selection.to);
|
||||
auto rangeTo = qMin(selection.to, blockFrom);
|
||||
if (rangeTo > rangeFrom) { // handle click handler
|
||||
QStringRef r = _text.midRef(rangeFrom, rangeTo - rangeFrom);
|
||||
if (lnkFrom != rangeFrom || blockFrom != rangeTo) {
|
||||
@@ -3018,7 +3013,16 @@ void Text::enumerateText(TextSelection selection, AppendPartCallback appendPartC
|
||||
clickHandlerStartCallback();
|
||||
}
|
||||
}
|
||||
if (i == e || blockFrom >= selection.to) break;
|
||||
|
||||
const auto checkBlockFlags = (blockFrom >= selection.from)
|
||||
&& (blockFrom <= selection.to);
|
||||
if (checkBlockFlags && blockFlags != flags) {
|
||||
flagsChangeCallback(flags, blockFlags);
|
||||
flags = blockFlags;
|
||||
}
|
||||
if (i == e || blockFrom >= selection.to) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*i)->type() == TextBlockTSkip) continue;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user