diff --git a/Telegram/Resources/art/sprite.png b/Telegram/Resources/art/sprite.png index 3417ad4ca..9c656af6b 100644 Binary files a/Telegram/Resources/art/sprite.png and b/Telegram/Resources/art/sprite.png differ diff --git a/Telegram/Resources/art/sprite_200x.png b/Telegram/Resources/art/sprite_200x.png index 5d386cc99..da7b930da 100644 Binary files a/Telegram/Resources/art/sprite_200x.png and b/Telegram/Resources/art/sprite_200x.png differ diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style index 8b8c4547f..e39737523 100644 --- a/Telegram/Resources/basic.style +++ b/Telegram/Resources/basic.style @@ -56,6 +56,7 @@ adaptiveNormalWidth: 640px; adaptiveWideWidth: 1366px; windowBg: #fff; // fallback for background: white +windowActiveBg: #40ace3; // fallback for blue filled active areas windowTextFg: #000; // fallback for text color: black windowSubTextFg: #8a8a8a; // fallback for subtext color: gray windowActiveTextFg: #1485c2; // fallback for active color: blue online @@ -114,6 +115,7 @@ defaultBoxButton: BoxButton { width: -24px; height: 36px; + padding: margins(0px, 0px, 0px, 0px); textTop: 8px; @@ -149,7 +151,7 @@ boxLabel: flatLabel(labelDefFlat) { defaultLeftOutlineButton: OutlineButton { outlineWidth: 3px; outlineFg: windowBg; - outlineFgOver: #3fb0e4; + outlineFgOver: windowActiveBg; textBg: windowBg; textBgOver: #f2f7fa; @@ -230,9 +232,9 @@ defaultCheckbox: Checkbox { textFg: black; textBg: white; - checkFg: #d9d9d9; - checkFgOver: #bfbfbf; - checkFgActive: #4eb3ee; + checkFg: #b3b3b3; + checkFgOver: #b3b3b3; + checkFgActive: #40ace3; width: -46px; height: 22px; @@ -240,7 +242,9 @@ defaultCheckbox: Checkbox { textPosition: point(34px, 0px); diameter: 22px; thickness: 2px; - checkIcon: sprite(106px, 136px, 14px, 10px); + checkIcon: icon { + { "default_checkbox_check", #ffffff, point(4px, 7px) } + }; font: boxTextFont; duration: 120; @@ -249,7 +253,7 @@ defaultRadiobutton: Radiobutton { textFg: black; textBg: white; - checkFg: #d9d9d9; + checkFg: #b3b3b3; checkFgOver: #bfbfbf; checkFgActive: #4eb3ee; @@ -908,46 +912,22 @@ btnLogout: flatButton(btnDefFlat, btnDefBig) { overFont: font(18px); } -//// dialogs -dlgFilterPadding: 10px; -dlgPhotoSize: 46px; -dlgPaddingHor: 10px; -dlgPaddingVer: 8px; -dlgHeight: 62px; -dlgPhotoPadding: 12px; - -dlgImportantHeight: 37px; - -noContactsHeight: 100px; -noContactsFont: font(fsize); -noContactsColor: #777; - -dlgSep: 8px; - -dlgMinWidth: 260px; -dlgRichMinWidth: 150px; -dlgMaxWidth: 540px; -dlgFilter: flatInput(inpDefGray) { +searchFlatInput: flatInput(inpDefGray) { font: font(fsize); - height: 34px; bgColor: #f2f2f2; phColor: #949494; phFocusColor: #a4a4a4; - textMrg: margins(34px, 2px, 34px, 4px); imgRect: sprite(227px, 21px, 24px, 24px); - imgPos: point(6px, 5px); - width: 240px; borderWidth: 2px; borderColor: #f2f2f2; borderActive: #80cff9; borderError: #ed8080; } -dlgScroll: flatScroll(scrollDef) { - topsh: 0px; - bottomsh: 0px; -} -dlgFont: font(fsize); + +noContactsHeight: 100px; +noContactsFont: font(fsize); +noContactsColor: #777; dlgDblCheckImg: sprite(302px, 23px, 17px, 11px); dlgCheckImg: sprite(320px, 23px, 17px, 11px); @@ -956,45 +936,17 @@ dlgActiveCheckImg: sprite(320px, 36px, 17px, 11px); dlgSendImg: sprite(122px, 25px, 17px, 11px); dlgActiveSendImg: sprite(142px, 25px, 17px, 11px); -dlgChatImgPos: point(1px, 4px); dlgChatImg: sprite(104px, 26px, 16px, 11px); dlgActiveChatImg: sprite(104px, 37px, 16px, 11px); -dlgChannelImgPos: point(3px, 4px); dlgChannelImg: sprite(105px, 1px, 12px, 11px); dlgActiveChannelImg: sprite(105px, 14px, 12px, 11px); -dlgImgSkip: 22px; -dlgCheckLeft: 5px; -dlgCheckTop: 4px; -dlgCheckSkip: 3px; - -dlgHistFont: font(fsize); -dlgNameColor: #000; -dlgNameTop: 2px; -dlgSystemColor: #4981af; -dlgTextColor: #888; - -dlgDateFont: font(13px); -dlgDateColor: #a8a8a8; -dlgDateSkip: 5px; - -dlgUnreadColor: #FFF; -dlgUnreadBG: #009ce6;//#6fc766; -dlgUnreadMutedBG: #bbb; -dlgUnreadFont: font(12px bold); -dlgUnreadHeight: 19px; -dlgUnreadTop: 1px; -dlgUnreadPaddingHor: 5px; -dlgUnreadRadius: 2px; -dlgBG: #FFF; -dlgHoverBG: #f5f5f5; - -dlgActiveBG: #6a91b1; -dlgActiveUnreadColor: #5b94bf; -dlgActiveUnreadBG: white; -dlgActiveColor: white; -dlgActiveDateColor: #d3e2ee; -dlgActiveUnreadMutedBG: dlgActiveDateColor; +dlgFilter: flatInput(searchFlatInput) { + width: 240px; + height: 34px; + textMrg: margins(34px, 2px, 34px, 4px); + imgPos: point(6px, 5px); +} topBarHeight: 54px; topBarBG: white; @@ -1024,24 +976,23 @@ topBarSearch: iconedButton(btnDefIconed) { height: topBarHeight; } topBarMinPadding: 5px; -topBarButton: flatButton(btnDefFlat) { - color: btnYesColor; - overColor: btnYesHover; - downColor: btnYesHover; +topBarButton: BoxButton { + textFg: #0084c4; + textFgOver: #0084c4; + textBg: white; + textBgOver: #edf4f7; - bgColor: white; - overBgColor: white; - downBgColor: white; + width: -22px; + height: 28px; + padding: margins(0px, 14px, 12px, 12px); - width: -40px; - height: 54px; - - textTop: 19px; - overTextTop: 19px; - downTextTop: 20px; + textTop: 6px; font: font(fsize); - overFont: font(fsize underline); + duration: 200; +} +topBarClearButton: BoxButton(topBarButton) { + padding: margins(8px, 14px, 8px, 14px); } topBarActionButton: flatButton(btnDefNext, btnDefBig) { textTop: 8px; @@ -1243,16 +1194,6 @@ medviewSaveAsTextStyle: textStyle(defaultTextStyle) { linkFgDown: #91d9ff; } -dlgTextStyle: textStyle(defaultTextStyle) { - linkFg: dlgSystemColor; - linkFgDown: dlgSystemColor; - linkFlagsOver: font(fsize); -} -dlgActiveTextStyle: textStyle(defaultTextStyle) { - linkFg: dlgActiveColor; - linkFgDown: dlgActiveColor; - linkFlagsOver: font(fsize); -} introLabelTextStyle: textStyle(defaultTextStyle) { lineHeight: 30px; } @@ -1538,16 +1479,24 @@ taMsgField: flatTextarea(taDefFlat) { maxFieldHeight: 220px; // historyMinHeight: 56px; -reportSpamHide: flatButton(topBarButton) { +reportSpamHide: flatButton(btnDefFlat) { + color: btnYesColor; + overColor: btnYesHover; + downColor: btnYesHover; + + bgColor: transparent; + overBgColor: transparent; + downBgColor: transparent; + + width: -40px; height: 46px; textTop: 15px; overTextTop: 15px; downTextTop: 16px; - bgColor: transparent; - overBgColor: transparent; - downBgColor: transparent; + font: font(fsize); + overFont: font(fsize underline); } reportSpamButton: flatButton(reportSpamHide) { textTop: 6px; @@ -1687,134 +1636,16 @@ confirmCompressedSkip: 10px; profileMaxWidth: 410px; profilePadding: margins(28px, 30px, 28px, 0px); -//profilePhotoSize: 120px; -//profileNameLeft: 21px; -//profileNameTop: -1px; -//profileNameFont: font(20px); -//profileStatusLeft: 22px; -//profileStatusTop: 31px; -//profileStatusFont: font(fsize); -profilePhoneLeft: 22px; -profilePhoneTop: 62px; -profilePhoneFont: font(16px); -//profileButtonTop: 18px; -//profileButtonSkip: 10px; -profileHeaderFont: font(20px); -profileHeaderColor: black; -profileHeaderSkip: 59px; -profileHeaderLeft: -1px; -profileHeaderTop: 22px; -profileListPhotoSize: 46px; -profileListPadding: size(12px, 6px); -profileListNameTop: 8px; -profileListStatusBottom: 6px; -profileHoverBG: #f5f5f5; -profileActiveBG: #6294b9; -profileSubFont: font(fsize); -profileListNameFont: semiboldFont; -profileListNameColor: #000; profileOnlineColor: titleTypingColor; profileOfflineColor: titleStatusColor; -btnShareContact: flatButton(btnDefNext, btnDefBig) { - width: 145px; - height: 42px; - - textTop: 9px; - overTextTop: 9px; - downTextTop: 10px; - - font: font(17px); - overFont: font(17px); -} -btnMigrateToMega: flatButton(btnShareContact) { - width: -40px; -} -profileMinBtnPadding: 10px; membersPadding: margins(0px, 10px, 0px, 10px); forwardMargins: margins(30px, 10px, 30px, 10px); forwardFont: font(16px); forwardBg: rgba(0, 0, 0, 76); -btnProfileCancel: flatButton(btnDefFlat, btnDefBig) { - color: #666d78; - overColor: #666d78; - downColor: #50565e; - bgColor: rgba(0, 0, 0, 63); - overBgColor: rgba(0, 0, 0, 47); - downBgColor: rgba(0, 0, 0, 95); - - width: 145px; - height: 40px; - - textTop: 9px; - overTextTop: 9px; - downTextTop: 10px; - - font: font(18px); - overFont: font(18px); -} - -btnDeleteContact: flatButton(btnDefFlat, btnDefBig) { - color: #fff; - overColor: #fff; - downColor: #ffcbc1; - - bgColor: #ee4928bf; - overBgColor: #ee4928; - downBgColor: #d14024; - - width: 300px; - height: 40px; - - textTop: 9px; - overTextTop: 9px; - downTextTop: 10px; - - font: font(18px); - overFont: font(18px); -} - -profileNameInput: flatInput(setNameInput) { - width: 230px; -} - -participantInnerAdd: flatButton(btnDefNext) { - width: 145px; - height: 40px; - font: font(18px); - overFont: font(18px); - textTop: 9px; - overTextTop: 9px; - downTextTop: 10px; -} -participantInnerCancel: flatButton(participantInnerAdd, btnDefBack) { -} -participantCancel: flatButton(participantInnerAdd, btnDefBack) { - width: 300px; -} -participantFilter: flatInput(inpDefFlat) { - width: 364px; - height: 52px; - font: font(16px); - textMrg: margins(39px, 11px, 10px, 10px); - imgRect: sprite(227px, 21px, 24px, 24px); - imgPos: point(10px, 15px); -} -participantDelta: 12px; - -contactsFilter: flatInput(dlgFilter) { - width: 340px; - height: 38px; - textMrg: margins(34px, 3px, 5px, 4px); - imgPos: point(6px, 7px); -} -inpCountry: flatInput(contactsFilter) { -} - -newGroupLimitFg: #a4a4a4; newGroupAboutFg: #808080; newGroupPadding: margins(4px, 6px, 4px, 3px); newGroupSkip: 17px; @@ -1855,15 +1686,6 @@ connectionPasswordInputField: InputField(defaultInputField) { } connectionIPv6Skip: 11px; -contactsAdd: flatButton(topBarButton) { - width: -40px; - height: 52px; - - textTop: 18px; - overTextTop: 18px; - downTextTop: 19px; -} - aboutIcon: sprite(0px, 0px, 104px, 104px); aboutWidth: 390px; aboutVersionTop: -3px; @@ -2131,8 +1953,6 @@ stickerPreviewDuration: 150; stickerPreviewBg: #FFFFFFB0; stickerPreviewMin: 0.1; -verifiedCheckProfile: sprite(285px, 235px, 18px, 18px); -verifiedCheckProfilePos: point(7px, 6px); verifiedCheck: sprite(285px, 221px, 14px, 14px); verifiedCheckInv: sprite(299px, 221px, 14px, 14px); verifiedCheckPos: point(4px, 2px); @@ -2419,7 +2239,7 @@ sessionNameFont: msgNameFont; sessionActiveFont: msgDateFont; sessionActiveColor: #aaa; sessionInfoFont: msgFont; -sessionInfoColor: dlgTextColor; +sessionInfoColor: #888888; sessionTerminateTop: 30px; sessionTerminateSkip: 18px; sessionTerminate: iconedButton(notifyClose) { diff --git a/Telegram/Resources/basic_types.style b/Telegram/Resources/basic_types.style index 4e2065ec7..000dec9fc 100644 --- a/Telegram/Resources/basic_types.style +++ b/Telegram/Resources/basic_types.style @@ -305,6 +305,7 @@ BoxButton { width: pixels; height: pixels; + padding: margins; textTop: pixels; @@ -328,7 +329,7 @@ Checkbox { textPosition: point; diameter: pixels; thickness: pixels; - checkIcon: sprite; + checkIcon: icon; font: font; duration: int; diff --git a/Telegram/Resources/icons/default_checkbox_check.png b/Telegram/Resources/icons/default_checkbox_check.png new file mode 100644 index 000000000..574f57123 Binary files /dev/null and b/Telegram/Resources/icons/default_checkbox_check.png differ diff --git a/Telegram/Resources/icons/default_checkbox_check@2x.png b/Telegram/Resources/icons/default_checkbox_check@2x.png new file mode 100644 index 000000000..6d3859c84 Binary files /dev/null and b/Telegram/Resources/icons/default_checkbox_check@2x.png differ diff --git a/Telegram/Resources/icons/dialogs_draft.png b/Telegram/Resources/icons/dialogs_draft.png deleted file mode 100644 index af8676033..000000000 Binary files a/Telegram/Resources/icons/dialogs_draft.png and /dev/null differ diff --git a/Telegram/Resources/icons/dialogs_draft@2x.png b/Telegram/Resources/icons/dialogs_draft@2x.png deleted file mode 100644 index 4b056d427..000000000 Binary files a/Telegram/Resources/icons/dialogs_draft@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/profile_admin_star.png b/Telegram/Resources/icons/profile_admin_star.png index 0e9d75e97..51e64b45e 100644 Binary files a/Telegram/Resources/icons/profile_admin_star.png and b/Telegram/Resources/icons/profile_admin_star.png differ diff --git a/Telegram/Resources/icons/profile_admin_star@2x.png b/Telegram/Resources/icons/profile_admin_star@2x.png index 97ba9c766..1e28af134 100644 Binary files a/Telegram/Resources/icons/profile_admin_star@2x.png and b/Telegram/Resources/icons/profile_admin_star@2x.png differ diff --git a/Telegram/Resources/icons/profile_verified_check.png b/Telegram/Resources/icons/profile_verified_check.png new file mode 100644 index 000000000..fafa4023a Binary files /dev/null and b/Telegram/Resources/icons/profile_verified_check.png differ diff --git a/Telegram/Resources/icons/profile_verified_check@2x.png b/Telegram/Resources/icons/profile_verified_check@2x.png new file mode 100644 index 000000000..790cc94cd Binary files /dev/null and b/Telegram/Resources/icons/profile_verified_check@2x.png differ diff --git a/Telegram/Resources/icons/profile_verified_star.png b/Telegram/Resources/icons/profile_verified_star.png new file mode 100644 index 000000000..ef20dc84b Binary files /dev/null and b/Telegram/Resources/icons/profile_verified_star.png differ diff --git a/Telegram/Resources/icons/profile_verified_star@2x.png b/Telegram/Resources/icons/profile_verified_star@2x.png new file mode 100644 index 000000000..967762a59 Binary files /dev/null and b/Telegram/Resources/icons/profile_verified_star@2x.png differ diff --git a/Telegram/Resources/icons/topbar_back_arrow.png b/Telegram/Resources/icons/topbar_back_arrow.png index 7c62fd73d..ab084438e 100644 Binary files a/Telegram/Resources/icons/topbar_back_arrow.png and b/Telegram/Resources/icons/topbar_back_arrow.png differ diff --git a/Telegram/Resources/icons/topbar_back_arrow@2x.png b/Telegram/Resources/icons/topbar_back_arrow@2x.png index 990a5bb66..22f148177 100644 Binary files a/Telegram/Resources/icons/topbar_back_arrow@2x.png and b/Telegram/Resources/icons/topbar_back_arrow@2x.png differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b7bc6b0ed..3ac7440c1 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -124,6 +124,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_flood_error" = "Too many tries. Please try again later."; "lng_gif_error" = "An error has occured while reading GIF animation :("; "lng_edit_error" = "You cannot edit this message"; +"lng_join_channel_error" = "Sorry, you have joined too many channels and supergroups. Please leave some before joining."; "lng_edit_deleted" = "This message was deleted"; "lng_edit_too_long" = "Your message text is too long"; "lng_edit_message" = "Edit message"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 9536c908d..661004e48 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -26,13 +26,16 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "application.h" #include "mainwindow.h" #include "mainwidget.h" +#include "historywidget.h" #include "localstorage.h" +#include "boxes/confirmbox.h" ApiWrap::ApiWrap(QObject *parent) : QObject(parent) , _messageDataResolveDelayed(new SingleDelayedCall(this, "resolveMessageDatas")) { App::initBackground(); connect(&_webPagesTimer, SIGNAL(timeout()), this, SLOT(resolveWebPages())); + connect(&_draftsSaveTimer, SIGNAL(timeout()), this, SLOT(saveDraftsToCloud())); } void ApiWrap::init() { @@ -717,6 +720,9 @@ void ApiWrap::channelAmInDone(ChannelData *channel, const MTPUpdates &updates) { bool ApiWrap::channelAmInFail(ChannelData *channel, const RPCError &error) { if (MTP::isDefaultHandledError(error)) return false; + if (error.type() == qstr("CHANNELS_TOO_MUCH")) { + Ui::showLayer(new InformBox(lang(lng_join_channel_error))); + } _channelAmInRequests.remove(channel); return true; } @@ -798,6 +804,83 @@ void ApiWrap::requestNotifySetting(PeerData *peer) { _notifySettingRequests.insert(peer, requestId); } +void ApiWrap::saveDraftToCloudDelayed(History *history) { + _draftsSaveRequestIds.insert(history, 0); + if (!_draftsSaveTimer.isActive()) { + _draftsSaveTimer.start(SaveCloudDraftTimeout); + } +} + +bool ApiWrap::hasUnsavedDrafts() const { + return !_draftsSaveRequestIds.isEmpty(); +} + +void ApiWrap::saveDraftsToCloud() { + for (auto i = _draftsSaveRequestIds.begin(), e = _draftsSaveRequestIds.end(); i != e; ++i) { + if (i.value()) continue; // sent already + + auto history = i.key(); + auto cloudDraft = history->cloudDraft(); + auto localDraft = history->localDraft(); + if (cloudDraft && cloudDraft->saveRequestId) { + MTP::cancel(cloudDraft->saveRequestId); + } + cloudDraft = history->createCloudDraft(localDraft); + + MTPmessages_SaveDraft::Flags flags = 0; + auto &textWithTags = cloudDraft->textWithTags; + if (cloudDraft->previewCancelled) { + flags |= MTPmessages_SaveDraft::Flag::f_no_webpage; + } + if (cloudDraft->msgId) { + flags |= MTPmessages_SaveDraft::Flag::f_reply_to_msg_id; + } + if (!textWithTags.tags.isEmpty()) { + flags |= MTPmessages_SaveDraft::Flag::f_entities; + } + auto entities = linksToMTP(entitiesFromTextTags(textWithTags.tags), true); + cloudDraft->saveRequestId = MTP::send(MTPmessages_SaveDraft(MTP_flags(flags), MTP_int(cloudDraft->msgId), history->peer->input, MTP_string(textWithTags.text), entities), rpcDone(&ApiWrap::saveCloudDraftDone, history), rpcFail(&ApiWrap::saveCloudDraftFail, history)); + i.value() = cloudDraft->saveRequestId; + } + if (_draftsSaveRequestIds.isEmpty()) { + App::allDraftsSaved(); // can quit the application + } +} + +void ApiWrap::saveCloudDraftDone(History *history, const MTPBool &result, mtpRequestId requestId) { + if (auto cloudDraft = history->cloudDraft()) { + if (cloudDraft->saveRequestId == requestId) { + cloudDraft->saveRequestId = 0; + history->updateChatListEntry(); + } + } + auto i = _draftsSaveRequestIds.find(history); + if (i != _draftsSaveRequestIds.cend() && i.value() == requestId) { + _draftsSaveRequestIds.remove(history); + if (_draftsSaveRequestIds.isEmpty()) { + App::allDraftsSaved(); // can quit the application + } + } +} + +bool ApiWrap::saveCloudDraftFail(History *history, const RPCError &error, mtpRequestId requestId) { + if (MTP::isDefaultHandledError(error)) return false; + + if (auto cloudDraft = history->cloudDraft()) { + if (cloudDraft->saveRequestId == requestId) { + history->clearCloudDraft(); + } + } + auto i = _draftsSaveRequestIds.find(history); + if (i != _draftsSaveRequestIds.cend() && i.value() == requestId) { + _draftsSaveRequestIds.remove(history); + if (_draftsSaveRequestIds.isEmpty()) { + App::allDraftsSaved(); // can quit the application + } + } + return true; +} + void ApiWrap::notifySettingDone(MTPInputNotifyPeer notifyPeer, const MTPPeerNotifySettings &result) { if (auto requestedPeer = notifySettingReceived(notifyPeer, result)) { _notifySettingRequests.remove(requestedPeer); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 0469e0139..e4c83a8d6 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -59,6 +59,9 @@ public: void exportInviteLink(PeerData *peer); void requestNotifySetting(PeerData *peer); + void saveDraftToCloudDelayed(History *history); + bool hasUnsavedDrafts() const; + ~ApiWrap(); signals: @@ -71,6 +74,7 @@ public slots: void resolveWebPages(); void delayedRequestParticipantsCount(); + void saveDraftsToCloud(); private: @@ -150,5 +154,9 @@ private: PeerData *notifySettingReceived(MTPInputNotifyPeer peer, const MTPPeerNotifySettings &settings); bool notifySettingFail(PeerData *peer, const RPCError &error); + QMap _draftsSaveRequestIds; + SingleTimer _draftsSaveTimer; + void saveCloudDraftDone(History *history, const MTPBool &result, mtpRequestId requestId); + bool saveCloudDraftFail(History *history, const RPCError &error, mtpRequestId requestId); }; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 13f1883c4..6aefddfa9 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2257,6 +2257,19 @@ namespace { if (quitting()) return; setLaunchState(QuitRequested); + if (auto window = wnd()) { + window->hide(); + } + if (auto mainwidget = main()) { + mainwidget->saveDraftToCloud(); + } + if (auto apiwrap = api()) { + if (apiwrap->hasUnsavedDrafts()) { + apiwrap->saveDraftsToCloud(); + QTimer::singleShot(SaveDraftBeforeQuitTimeout, Application::instance(), SLOT(quit())); + return; + } + } Application::quit(); } @@ -2264,6 +2277,12 @@ namespace { return _launchState != Launched; } + void allDraftsSaved() { + if (quitting()) { + Application::quit(); + } + } + LaunchState launchState() { return _launchState; } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 3ce9600e0..5613e68b2 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -228,6 +228,7 @@ namespace App { }; void quit(); bool quitting(); + void allDraftsSaved(); LaunchState launchState(); void setLaunchState(LaunchState state); diff --git a/Telegram/SourceFiles/boxes/photosendbox.cpp b/Telegram/SourceFiles/boxes/photosendbox.cpp index f3e6b47d0..b8c9608b7 100644 --- a/Telegram/SourceFiles/boxes/photosendbox.cpp +++ b/Telegram/SourceFiles/boxes/photosendbox.cpp @@ -656,7 +656,8 @@ void EditCaptionBox::onSave(bool ctrlShiftEnter) { if (!sentEntities.c_vector().v.isEmpty()) { flags |= MTPmessages_EditMessage::Flag::f_entities; } - _saveRequestId = MTP::send(MTPmessages_EditMessage(MTP_flags(flags), item->history()->peer->input, MTP_int(item->id), MTP_string(_field->getLastText()), MTPnullMarkup, sentEntities), rpcDone(&EditCaptionBox::saveDone), rpcFail(&EditCaptionBox::saveFail)); + auto text = prepareText(_field->getLastText(), true); + _saveRequestId = MTP::send(MTPmessages_EditMessage(MTP_flags(flags), item->history()->peer->input, MTP_int(item->id), MTP_string(text), MTPnullMarkup, sentEntities), rpcDone(&EditCaptionBox::saveDone), rpcFail(&EditCaptionBox::saveFail)); } void EditCaptionBox::saveDone(const MTPUpdates &updates) { diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 1ee892abe..93119734f 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -151,8 +151,10 @@ enum { WriteMapTimeout = 1000, SaveDraftTimeout = 1000, // save draft after 1 secs of not changing text - SaveCloudDraftTimeout = 14000, // save draft to the cloud after 14 more seconds SaveDraftAnywayTimeout = 5000, // or save anyway each 5 secs + SaveCloudDraftIdleTimeout = 14000, // save draft to the cloud after 14 more seconds + SaveCloudDraftTimeout = 1000, // save draft to the cloud with 1 sec extra delay + SaveDraftBeforeQuitTimeout = 1500, // give the app 1.5 secs to save drafts to cloud when quitting SetOnlineAfterActivity = 30, // user with hidden last seen stays online for such amount of seconds in the interface diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 4989619dc..c65fa301c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -19,7 +19,69 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ using "basic.style"; +using "basic_types.style"; -dialogsDraft: icon { - { "dialogs_draft", #ffffff, point(5px, 4px) }, -}; +dialogsUnreadFg: #ffffff; +dialogsUnreadFgActive: #5b94bf; +dialogsUnreadBg: #009ce6;//#6fc766; +dialogsUnreadBgMuted: #bbb; +dialogsUnreadBgActive: #ffffff; +dialogsUnreadBgMutedActive: #d3e2ee; +dialogsUnreadFont: font(12px bold); +dialogsUnreadHeight: 19px; +dialogsUnreadTop: 1px; +dialogsUnreadPadding: 5px; + +dialogsBg: windowBg; +dialogsBgOver: #f5f5f5; +dialogsBgActive: #6a91b1; +dialogsTextFont: font(fsize); +dialogsTextFg: #888888; +dialogsTextFgService: #4981af; +dialogsTextFgActive: #ffffff; +dialogsDateFont: font(13px); +dialogsDateFgActive: #ffffff; +dialogsDateFg: #a8a8a8; +dialogsDateSkip: 5px; +dialogsNameFg: #000; +dialogsNameTop: 2px; + +dialogsRowHeight: 62px; +dialogsFilterPadding: 10px; +dialogsPhotoSize: 46px; +dialogsPhotoPadding: 12px; +dialogsPadding: point(10px, 8px); + +dialogsImportantBarHeight: 37px; + +dialogsSkip: 8px; + +dialogsWidthMin: 260px; +dialogsWidthMax: 540px; +dialogsTextWidthMin: 150px; +dialogsScroll: flatScroll(scrollDef) { + topsh: 0px; + bottomsh: 0px; +} + +dialogsChatImgPos: point(1px, 4px); +dialogsChannelImgPos: point(3px, 4px); +dialogsImgSkip: 22px; + +dialogsCheckLeft: 5px; +dialogsCheckTop: 4px; +dialogsCheckSkip: 3px; + +dialogsTextStyle: textStyle(defaultTextStyle) { + linkFg: dialogsTextFgService; + linkFgDown: dialogsTextFgService; + linkFlagsOver: font(fsize); +} +dialogsTextStyleDraft: textStyle(dialogsTextStyle) { + linkFg: #dd4b39; + linkFgDown: #dd4b39; +} +dialogsTextStyleActive: textStyle(dialogsTextStyle) { + linkFg: dialogsTextFgActive; + linkFgDown: dialogsTextFgActive; +} diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 5057ec3df..8d17dabcd 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -42,80 +42,68 @@ void paintRowDate(Painter &p, const QDateTime &date, QRect &rectForName, bool ac } else { dt = lastDate.toString(qsl("d.MM.yy")); } - int32 dtWidth = st::dlgDateFont->width(dt); - rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip); - p.setFont(st::dlgDateFont); - p.setPen(active ? st::dlgActiveDateColor : st::dlgDateColor); - p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt); + int32 dtWidth = st::dialogsDateFont->width(dt); + rectForName.setWidth(rectForName.width() - dtWidth - st::dialogsDateSkip); + p.setFont(st::dialogsDateFont); + p.setPen(active ? st::dialogsDateFgActive : st::dialogsDateFg); + p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt); } template void paintRow(Painter &p, History *history, HistoryItem *item, HistoryDraft *draft, int w, bool active, bool selected, bool onlyBackground, PaintItemCallback paintItemCallback) { - QRect fullRect(0, 0, w, st::dlgHeight); - p.fillRect(fullRect, active ? st::dlgActiveBG : (selected ? st::dlgHoverBG : st::dlgBG)); + QRect fullRect(0, 0, w, st::dialogsRowHeight); + p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg)); if (onlyBackground) return; PeerData *userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer); - userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, w); + userpicPeer->paintUserpicLeft(p, st::dialogsPhotoSize, st::dialogsPadding.x(), st::dialogsPadding.y(), w); - int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding; - int32 namewidth = w - nameleft - st::dlgPaddingHor; - QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height); + int32 nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding; + int32 namewidth = w - nameleft - st::dialogsPadding.x(); + QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height); // draw chat icon if (history->peer->isChat() || history->peer->isMegagroup()) { - p.drawSprite(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), (active ? st::dlgActiveChatImg : st::dlgChatImg)); - rectForName.setLeft(rectForName.left() + st::dlgImgSkip); + p.drawSprite(QPoint(rectForName.left() + st::dialogsChatImgPos.x(), rectForName.top() + st::dialogsChatImgPos.y()), (active ? st::dlgActiveChatImg : st::dlgChatImg)); + rectForName.setLeft(rectForName.left() + st::dialogsImgSkip); } else if (history->peer->isChannel()) { - p.drawSprite(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), (active ? st::dlgActiveChannelImg : st::dlgChannelImg)); - rectForName.setLeft(rectForName.left() + st::dlgImgSkip); + p.drawSprite(QPoint(rectForName.left() + st::dialogsChannelImgPos.x(), rectForName.top() + st::dialogsChannelImgPos.y()), (active ? st::dlgActiveChannelImg : st::dlgChannelImg)); + rectForName.setLeft(rectForName.left() + st::dialogsImgSkip); } - int texttop = st::dlgPaddingVer + st::dlgFont->height + st::dlgSep; + int texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip; if (draft) { paintRowDate(p, draft->date, rectForName, active); // draw check if (draft->saveRequestId) { auto check = active ? &st::dlgActiveSendImg : &st::dlgSendImg; - rectForName.setWidth(rectForName.width() - check->pxWidth() - st::dlgCheckSkip); - p.drawSprite(QPoint(rectForName.left() + rectForName.width() + st::dlgCheckLeft, rectForName.top() + st::dlgCheckTop), *check); + rectForName.setWidth(rectForName.width() - check->pxWidth() - st::dialogsCheckSkip); + p.drawSprite(QPoint(rectForName.left() + rectForName.width() + st::dialogsCheckLeft, rectForName.top() + st::dialogsCheckTop), *check); } - bool hasDraftIcon = !active; - if (hasDraftIcon) { - QString counter; - bool mutedCounter = false; - int unreadRight = w - st::dlgPaddingHor; - int unreadTop = texttop + st::dlgHistFont->ascent - st::dlgUnreadFont->ascent - st::dlgUnreadTop; - int unreadWidth = 0; - paintUnreadCount(p, counter, unreadRight, unreadTop, style::al_right, active, mutedCounter, &unreadWidth); - st::dialogsDraft.paint(p, QPoint(w - st::dlgPaddingHor - st::dlgUnreadHeight, unreadTop), w); - namewidth -= unreadWidth + st::dlgUnreadPaddingHor; - } - - p.setFont(st::dlgHistFont); - p.setPen(active ? st::dlgActiveColor : st::dlgSystemColor); + p.setFont(st::dialogsTextFont); + p.setPen(active ? st::dialogsTextFgActive : st::dialogsTextFgService); if (history->typing.isEmpty() && history->sendActions.isEmpty()) { if (history->cloudDraftTextCache.isEmpty()) { TextCustomTagsMap custom; custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink())); QString msg = lng_message_with_from(lt_from, textRichPrepare(lang(lng_from_draft)), lt_message, textRichPrepare(draft->textWithTags.text)); - history->cloudDraftTextCache.setRichText(st::dlgHistFont, msg, _textDlgOptions, custom); + history->cloudDraftTextCache.setRichText(st::dialogsTextFont, msg, _textDlgOptions, custom); } - textstyleSet(&(active ? st::dlgActiveTextStyle : st::dlgTextStyle)); - p.setFont(st::dlgHistFont); - p.setPen(active ? st::dlgActiveColor : st::dlgTextColor); - history->cloudDraftTextCache.drawElided(p, nameleft, texttop, namewidth, st::dlgFont->height / st::dlgHistFont->height); + textstyleSet(&(active ? st::dialogsTextStyleActive : st::dialogsTextStyleDraft)); + p.setFont(st::dialogsTextFont); + p.setPen(active ? st::dialogsTextFgActive : st::dialogsTextFg); + history->cloudDraftTextCache.drawElided(p, nameleft, texttop, namewidth, 1); textstyleRestore(); } else { history->typingText.drawElided(p, nameleft, texttop, namewidth); } } else if (!item) { - p.setFont(st::dlgHistFont); - p.setPen(active ? st::dlgActiveColor : st::dlgSystemColor); + p.setFont(st::dialogsTextFont); + p.setPen(active ? st::dialogsTextFgActive : st::dialogsTextFgService); if (history->typing.isEmpty() && history->sendActions.isEmpty()) { - p.drawText(nameleft, texttop + st::dlgFont->ascent, lang(lng_empty_history)); + p.drawText(nameleft, texttop + st::msgNameFont->ascent, lang(lng_empty_history)); } else { history->typingText.drawElided(p, nameleft, texttop, namewidth); } @@ -134,8 +122,8 @@ void paintRow(Painter &p, History *history, HistoryItem *item, HistoryDraft *dra } else { check = active ? &st::dlgActiveSendImg : &st::dlgSendImg; } - rectForName.setWidth(rectForName.width() - check->pxWidth() - st::dlgCheckSkip); - p.drawSprite(QPoint(rectForName.left() + rectForName.width() + st::dlgCheckLeft, rectForName.top() + st::dlgCheckTop), *check); + rectForName.setWidth(rectForName.width() - check->pxWidth() - st::dialogsCheckSkip); + p.drawSprite(QPoint(rectForName.left() + rectForName.width() + st::dialogsCheckLeft, rectForName.top() + st::dialogsCheckTop), *check); } paintItemCallback(nameleft, namewidth, item); @@ -146,7 +134,7 @@ void paintRow(Painter &p, History *history, HistoryItem *item, HistoryDraft *dra p.drawSprite(rectForName.topLeft() + QPoint(qMin(history->peer->dialogName().maxWidth(), rectForName.width()), 0) + st::verifiedCheckPos, (active ? st::verifiedCheckInv : st::verifiedCheck)); } - p.setPen(active ? st::dlgActiveColor : st::dlgNameColor); + p.setPen(active ? st::dialogsTextFgActive : st::dialogsNameFg); history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); } @@ -154,7 +142,7 @@ class UnreadBadgeStyle : public StyleSheet { public: QImage circle; QPixmap left[4], right[4]; - style::color bg[4] = { st::dlgUnreadBG, st::dlgActiveUnreadBG, st::dlgUnreadMutedBG, st::dlgActiveUnreadMutedBG }; + style::color bg[4] = { st::dialogsUnreadBg, st::dialogsUnreadBgActive, st::dialogsUnreadBgMuted, st::dialogsUnreadBgMutedActive }; }; StyleSheetPointer unreadBadgeStyle; @@ -203,9 +191,9 @@ void paintUnreadBadge(Painter &p, const QRect &rect, bool active, bool muted) { } void paintUnreadCount(Painter &p, const QString &text, int x, int y, style::align align, bool active, bool muted, int *outUnreadWidth) { - int unreadWidth = st::dlgUnreadFont->width(text); - int unreadRectWidth = unreadWidth + 2 * st::dlgUnreadPaddingHor; - int unreadRectHeight = st::dlgUnreadHeight; + int unreadWidth = st::dialogsUnreadFont->width(text); + int unreadRectWidth = unreadWidth + 2 * st::dialogsUnreadPadding; + int unreadRectHeight = st::dialogsUnreadHeight; accumulate_max(unreadRectWidth, unreadRectHeight); int unreadRectLeft = x; @@ -221,9 +209,9 @@ void paintUnreadCount(Painter &p, const QString &text, int x, int y, style::alig paintUnreadBadge(p, QRect(unreadRectLeft, unreadRectTop, unreadRectWidth, unreadRectHeight), active, muted); - p.setFont(st::dlgUnreadFont); - p.setPen(active ? st::dlgActiveUnreadColor : st::dlgUnreadColor); - p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + st::dlgUnreadTop + st::dlgUnreadFont->ascent, text); + p.setFont(st::dialogsUnreadFont); + p.setPen(active ? st::dialogsUnreadFgActive : st::dialogsUnreadFg); + p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + st::dialogsUnreadTop + st::dialogsUnreadFont->ascent, text); } void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) { @@ -241,30 +229,20 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele } } int availableWidth = namewidth; - int texttop = st::dlgPaddingVer + st::dlgFont->height + st::dlgSep; - auto cloudDraft = history->cloudDraft(); - bool hasDraftIcon = active ? false : (cloudDraft && cloudDraft->date.isValid()); - if (unread || hasDraftIcon) { - QString counter; - bool mutedCounter = false; - bool showUnreadCounter = unread && (!hasDraftIcon || !history->mute()); - if (showUnreadCounter) { - counter = QString::number(unread); - mutedCounter = history->mute(); - } - int unreadRight = w - st::dlgPaddingHor; - int unreadTop = texttop + st::dlgHistFont->ascent - st::dlgUnreadFont->ascent - st::dlgUnreadTop; + int texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip; + if (unread) { + auto counter = QString::number(unread); + auto mutedCounter = history->mute(); + int unreadRight = w - st::dialogsPadding.x(); + int unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - st::dialogsUnreadTop; int unreadWidth = 0; paintUnreadCount(p, counter, unreadRight, unreadTop, style::al_right, active, mutedCounter, &unreadWidth); - if (!showUnreadCounter) { - st::dialogsDraft.paint(p, QPoint(w - st::dlgPaddingHor - st::dlgUnreadHeight, unreadTop), w); - } - availableWidth -= unreadWidth + st::dlgUnreadPaddingHor; + availableWidth -= unreadWidth + st::dialogsUnreadPadding; } if (history->typing.isEmpty() && history->sendActions.isEmpty()) { - item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dlgFont->height), active, history->textCachedFor, history->lastItemTextCache); + item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dialogsTextFont->height), active, history->textCachedFor, history->lastItemTextCache); } else { - p.setPen(active ? st::dlgActiveColor : st::dlgSystemColor); + p.setPen(active ? st::dialogsTextFgActive : st::dialogsTextFgService); history->typingText.drawElided(p, nameleft, texttop, availableWidth); } }); @@ -274,13 +252,13 @@ void RowPainter::paint(Painter &p, const FakeRow *row, int w, bool active, bool auto item = row->item(); auto history = item->history(); paintRow(p, history, item, nullptr, w, active, selected, onlyBackground, [&p, row, active](int nameleft, int namewidth, HistoryItem *item) { - int lastWidth = namewidth, texttop = st::dlgPaddingVer + st::dlgFont->height + st::dlgSep; - item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dlgFont->height), active, row->_cacheFor, row->_cache); + int lastWidth = namewidth, texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip; + item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dialogsTextFont->height), active, row->_cacheFor, row->_cache); }); } void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool onlyBackground) { - p.fillRect(0, 0, w, st::dlgImportantHeight, selected ? st::dlgHoverBG : st::white); + p.fillRect(0, 0, w, st::dialogsImportantBarHeight, selected ? st::dialogsBgOver : st::white); if (onlyBackground) { return; } @@ -288,15 +266,15 @@ void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool o p.setFont(st::semiboldFont); p.setPen(st::black); - int unreadTop = (st::dlgImportantHeight - st::dlgUnreadHeight) / 2; + int unreadTop = (st::dialogsImportantBarHeight - st::dialogsUnreadHeight) / 2; bool mutedHidden = (current == Dialogs::Mode::Important); QString text = mutedHidden ? qsl("Show all chats") : qsl("Hide muted chats"); - int textBaseline = unreadTop + st::dlgUnreadTop + st::dlgUnreadFont->ascent; - p.drawText(st::dlgPaddingHor, textBaseline, text); + int textBaseline = unreadTop + st::dialogsUnreadTop + st::dialogsUnreadFont->ascent; + p.drawText(st::dialogsPadding.x(), textBaseline, text); if (mutedHidden) { if (int32 unread = App::histories().unreadMutedCount()) { - int unreadRight = w - st::dlgPaddingHor; + int unreadRight = w - st::dialogsPadding.x(); paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, style::al_right, false, true, nullptr); } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_list.cpp b/Telegram/SourceFiles/dialogs/dialogs_list.cpp index 12591987a..e230f53ef 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_list.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_list.cpp @@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "dialogs/dialogs_list.h" #include "dialogs/dialogs_layout.h" +#include "styles/style_dialogs.h" #include "mainwidget.h" namespace Dialogs { @@ -47,16 +48,16 @@ void List::adjustCurrent(int32 y, int32 h) const { } void List::paint(Painter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel, bool onlyBackground) const { - adjustCurrent(hFrom, st::dlgHeight); + adjustCurrent(hFrom, st::dialogsRowHeight); Row *row = _current; - p.translate(0, row->_pos * st::dlgHeight); - while (row != _end && row->_pos * st::dlgHeight < hTo) { + p.translate(0, row->_pos * st::dialogsRowHeight); + while (row != _end && row->_pos * st::dialogsRowHeight < hTo) { bool active = (row->history()->peer == act) || (row->history()->peer->migrateTo() && row->history()->peer->migrateTo() == act); bool selected = (row->history()->peer == sel); Layout::RowPainter::paint(p, row, w, active, selected, onlyBackground); row = row->_next; - p.translate(0, st::dlgHeight); + p.translate(0, st::dialogsRowHeight); } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp new file mode 100644 index 000000000..74de183a6 --- /dev/null +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -0,0 +1,31 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "dialogs/dialogs_row.h" + +#include "styles/style_dialogs.h" + +namespace Dialogs { + +FakeRow::FakeRow(HistoryItem *item) : _item(item), _cache(st::dialogsTextWidthMin) { +} + +} // namespace Dialogs \ No newline at end of file diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.h b/Telegram/SourceFiles/dialogs/dialogs_row.h index 45180f4ff..7327f094e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.h +++ b/Telegram/SourceFiles/dialogs/dialogs_row.h @@ -59,8 +59,7 @@ private: class FakeRow { public: - FakeRow(HistoryItem *item) : _item(item) { - } + FakeRow(HistoryItem *item); HistoryItem *item() const { return _item; @@ -71,7 +70,7 @@ private: HistoryItem *_item; mutable const HistoryItem *_cacheFor = nullptr; - mutable Text _cache = Text{ int(st::dlgRichMinWidth) }; + mutable Text _cache; }; diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 350f10dab..df2612fd3 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "dialogs/dialogs_indexed_list.h" #include "dialogs/dialogs_layout.h" +#include "styles/style_dialogs.h" #include "data/drafts.h" #include "lang.h" #include "application.h" @@ -55,7 +56,7 @@ DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(p } int DialogsInner::dialogsOffset() const { - return importantDialogs ? st::dlgImportantHeight : 0; + return importantDialogs ? st::dialogsImportantBarHeight : 0; } int DialogsInner::filteredOffset() const { @@ -63,12 +64,12 @@ int DialogsInner::filteredOffset() const { } int DialogsInner::peopleOffset() const { - return filteredOffset() + (_filterResults.size() * st::dlgHeight) + st::searchedBarHeight; + return filteredOffset() + (_filterResults.size() * st::dialogsRowHeight) + st::searchedBarHeight; } int DialogsInner::searchedOffset() const { - int result = peopleOffset() + (_peopleResults.isEmpty() ? 0 : ((_peopleResults.size() * st::dlgHeight) + st::searchedBarHeight)); - if (_searchInPeer) result += st::dlgHeight; + int result = peopleOffset() + (_peopleResults.isEmpty() ? 0 : ((_peopleResults.size() * st::dialogsRowHeight) + st::searchedBarHeight)); + if (_searchInPeer) result += st::dialogsRowHeight; return result; } @@ -87,10 +88,10 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO QRect dialogsClip = r; if (importantDialogs) { Dialogs::Layout::paintImportantSwitch(p, Global::DialogsMode(), fullWidth(), _importantSwitchSel, paintingOther); - dialogsClip.translate(0, -st::dlgImportantHeight); - p.translate(0, st::dlgImportantHeight); + dialogsClip.translate(0, -st::dialogsImportantBarHeight); + p.translate(0, st::dialogsImportantBarHeight); } - int32 otherStart = shownDialogs()->size() * st::dlgHeight; + int32 otherStart = shownDialogs()->size() * st::dialogsRowHeight; PeerData *active = App::main()->activePeer(), *selected = _menuPeer ? _menuPeer : (_sel ? _sel->history()->peer : 0); if (otherStart) { shownDialogs()->all().paint(p, fullWidth(), dialogsClip.top(), dialogsClip.top() + dialogsClip.height(), active, selected, paintingOther); @@ -109,7 +110,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO int32 to = ceilclamp(r.y() + r.height(), st::mentionHeight, 0, _hashtagResults.size()); p.translate(0, from * st::mentionHeight); if (from < _hashtagResults.size()) { - int32 w = fullWidth(), htagwidth = w - st::dlgPaddingHor * 2; + int32 w = fullWidth(), htagwidth = w - st::dialogsPadding.x() * 2; p.setFont(st::mentionFont->f); p.setPen(st::black->p); @@ -135,11 +136,11 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO p.setFont(st::mentionFont->f); if (!first.isEmpty()) { p.setPen((selected ? st::mentionFgOverActive : st::mentionFgActive)->p); - p.drawText(st::dlgPaddingHor, st::mentionTop + st::mentionFont->ascent, first); + p.drawText(st::dialogsPadding.x(), st::mentionTop + st::mentionFont->ascent, first); } if (!second.isEmpty()) { p.setPen((selected ? st::mentionFgOver : st::mentionFg)->p); - p.drawText(st::dlgPaddingHor + firstwidth, st::mentionTop + st::mentionFont->ascent, second); + p.drawText(st::dialogsPadding.x() + firstwidth, st::mentionTop + st::mentionFont->ascent, second); } } p.translate(0, st::mentionHeight); @@ -148,9 +149,9 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO } if (!_filterResults.isEmpty()) { int32 skip = filteredOffset(); - int32 from = floorclamp(r.y() - skip, st::dlgHeight, 0, _filterResults.size()); - int32 to = ceilclamp(r.y() + r.height() - skip, st::dlgHeight, 0, _filterResults.size()); - p.translate(0, from * st::dlgHeight); + int32 from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _filterResults.size()); + int32 to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _filterResults.size()); + p.translate(0, from * st::dialogsRowHeight); if (from < _filterResults.size()) { int32 w = fullWidth(); PeerData *act = App::main()->activePeer(); @@ -159,7 +160,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO bool active = ((_filterResults[from]->history()->peer == act) || (_filterResults[from]->history()->peer->migrateTo() && _filterResults[from]->history()->peer->migrateTo() == act)) && !actId; bool selected = (from == _filteredSel) || (_filterResults[from]->history()->peer == _menuPeer); Dialogs::Layout::RowPainter::paint(p, _filterResults[from], w, active, selected, paintingOther); - p.translate(0, st::dlgHeight); + p.translate(0, st::dialogsRowHeight); } } } @@ -174,9 +175,9 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO p.translate(0, st::searchedBarHeight); int32 skip = peopleOffset(); - int32 from = floorclamp(r.y() - skip, st::dlgHeight, 0, _peopleResults.size()); - int32 to = ceilclamp(r.y() + r.height() - skip, st::dlgHeight, 0, _peopleResults.size()); - p.translate(0, from * st::dlgHeight); + int32 from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _peopleResults.size()); + int32 to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _peopleResults.size()); + p.translate(0, from * st::dialogsRowHeight); if (from < _peopleResults.size()) { int32 w = fullWidth(); PeerData *act = App::main()->activePeer(); @@ -185,14 +186,14 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO bool active = ((_peopleResults[from] == act) || (_peopleResults[from]->migrateTo() && _peopleResults[from]->migrateTo() == act)) && !actId; bool selected = (from == _peopleSel); peopleResultPaint(_peopleResults[from], p, w, active, selected, paintingOther); - p.translate(0, st::dlgHeight); + p.translate(0, st::dialogsRowHeight); } } } if (_searchInPeer) { searchInPeerPaint(p, fullWidth(), paintingOther); - p.translate(0, st::dlgHeight); + p.translate(0, st::dialogsRowHeight); if (_state == FilteredState && _searchResults.isEmpty()) { p.fillRect(0, 0, fullWidth(), st::searchedBarHeight, st::searchedBarBG->b); if (!paintingOther) { @@ -215,9 +216,9 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO p.translate(0, st::searchedBarHeight); int32 skip = searchedOffset(); - int32 from = floorclamp(r.y() - skip, st::dlgHeight, 0, _searchResults.size()); - int32 to = ceilclamp(r.y() + r.height() - skip, st::dlgHeight, 0, _searchResults.size()); - p.translate(0, from * st::dlgHeight); + int32 from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _searchResults.size()); + int32 to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _searchResults.size()); + p.translate(0, from * st::dialogsRowHeight); if (from < _searchResults.size()) { int32 w = fullWidth(); PeerData *act = App::main()->activePeer(); @@ -229,7 +230,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO bool active = (history->peer == act && item->id == actId) || (history->peer->migrateTo() && history->peer->migrateTo() == act && item->id == -actId); bool selected = (from == _searchedSel); Dialogs::Layout::RowPainter::paint(p, result, w, active, selected, paintingOther); - p.translate(0, st::dlgHeight); + p.translate(0, st::dialogsRowHeight); } } } @@ -237,80 +238,80 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO } void DialogsInner::peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool active, bool selected, bool onlyBackground) const { - QRect fullRect(0, 0, w, st::dlgHeight); - p.fillRect(fullRect, active ? st::dlgActiveBG : (selected ? st::dlgHoverBG : st::dlgBG)); + QRect fullRect(0, 0, w, st::dialogsRowHeight); + p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg)); if (onlyBackground) return; PeerData *userpicPeer = (peer->migrateTo() ? peer->migrateTo() : peer); - userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, fullWidth()); + userpicPeer->paintUserpicLeft(p, st::dialogsPhotoSize, st::dialogsPadding.x(), st::dialogsPadding.y(), fullWidth()); - int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding; - int32 namewidth = w - nameleft - st::dlgPaddingHor; - QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height); + int32 nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding; + int32 namewidth = w - nameleft - st::dialogsPadding.x(); + QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height); // draw chat icon if (peer->isChat() || peer->isMegagroup()) { - p.drawSprite(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), (active ? st::dlgActiveChatImg : st::dlgChatImg)); - rectForName.setLeft(rectForName.left() + st::dlgImgSkip); + p.drawSprite(QPoint(rectForName.left() + st::dialogsChatImgPos.x(), rectForName.top() + st::dialogsChatImgPos.y()), (active ? st::dlgActiveChatImg : st::dlgChatImg)); + rectForName.setLeft(rectForName.left() + st::dialogsImgSkip); } else if (peer->isChannel()) { - p.drawSprite(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), (active ? st::dlgActiveChannelImg : st::dlgChannelImg)); - rectForName.setLeft(rectForName.left() + st::dlgImgSkip); + p.drawSprite(QPoint(rectForName.left() + st::dialogsChannelImgPos.x(), rectForName.top() + st::dialogsChannelImgPos.y()), (active ? st::dlgActiveChannelImg : st::dlgChannelImg)); + rectForName.setLeft(rectForName.left() + st::dialogsImgSkip); } if (peer->isVerified()) { rectForName.setWidth(rectForName.width() - st::verifiedCheck.pxWidth() - st::verifiedCheckPos.x()); p.drawSprite(rectForName.topLeft() + QPoint(qMin(peer->dialogName().maxWidth(), rectForName.width()), 0) + st::verifiedCheckPos, (active ? st::verifiedCheckInv : st::verifiedCheck)); } - QRect tr(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, namewidth, st::dlgFont->height); - p.setFont(st::dlgHistFont->f); + QRect tr(nameleft, st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip, namewidth, st::dialogsTextFont->height); + p.setFont(st::dialogsTextFont); QString username = peer->userName(); if (!active && username.toLower().startsWith(_peopleQuery)) { QString first = '@' + username.mid(0, _peopleQuery.size()), second = username.mid(_peopleQuery.size()); - int32 w = st::dlgHistFont->width(first); + int32 w = st::dialogsTextFont->width(first); if (w >= tr.width()) { - p.setPen(st::dlgSystemColor->p); - p.drawText(tr.left(), tr.top() + st::dlgHistFont->ascent, st::dlgHistFont->elided(first, tr.width())); + p.setPen(st::dialogsTextFgService); + p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided(first, tr.width())); } else { - p.setPen(st::dlgSystemColor->p); - p.drawText(tr.left(), tr.top() + st::dlgHistFont->ascent, first); - p.setPen(st::dlgTextColor->p); - p.drawText(tr.left() + w, tr.top() + st::dlgHistFont->ascent, st::dlgHistFont->elided(second, tr.width() - w)); + p.setPen(st::dialogsTextFgService); + p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, first); + p.setPen(st::dialogsTextFg); + p.drawText(tr.left() + w, tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided(second, tr.width() - w)); } } else { - p.setPen((active ? st::dlgActiveColor : st::dlgSystemColor)->p); - p.drawText(tr.left(), tr.top() + st::dlgHistFont->ascent, st::dlgHistFont->elided('@' + username, tr.width())); + p.setPen(active ? st::dialogsTextFgActive : st::dialogsTextFgService); + p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided('@' + username, tr.width())); } - p.setPen((active ? st::dlgActiveColor : st::dlgNameColor)->p); + p.setPen(active ? st::dialogsTextFgActive : st::dialogsNameFg); peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); } void DialogsInner::searchInPeerPaint(Painter &p, int32 w, bool onlyBackground) const { - QRect fullRect(0, 0, w, st::dlgHeight); - p.fillRect(fullRect, st::dlgBG->b); + QRect fullRect(0, 0, w, st::dialogsRowHeight); + p.fillRect(fullRect, st::dialogsBg); if (onlyBackground) return; - _searchInPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, fullWidth()); + _searchInPeer->paintUserpicLeft(p, st::dialogsPhotoSize, st::dialogsPadding.x(), st::dialogsPadding.y(), fullWidth()); - int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding; - int32 namewidth = w - nameleft - st::dlgPaddingHor * 2 - st::btnCancelSearch.width; - QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height); + int32 nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding; + int32 namewidth = w - nameleft - st::dialogsPadding.x() * 2 - st::btnCancelSearch.width; + QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height); // draw chat icon if (_searchInPeer->isChat() || _searchInPeer->isMegagroup()) { - p.drawSprite(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), st::dlgChatImg); - rectForName.setLeft(rectForName.left() + st::dlgImgSkip); + p.drawSprite(QPoint(rectForName.left() + st::dialogsChatImgPos.x(), rectForName.top() + st::dialogsChatImgPos.y()), st::dlgChatImg); + rectForName.setLeft(rectForName.left() + st::dialogsImgSkip); } else if (_searchInPeer->isChannel()) { - p.drawSprite(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), st::dlgChannelImg); - rectForName.setLeft(rectForName.left() + st::dlgImgSkip); + p.drawSprite(QPoint(rectForName.left() + st::dialogsChannelImgPos.x(), rectForName.top() + st::dialogsChannelImgPos.y()), st::dlgChannelImg); + rectForName.setLeft(rectForName.left() + st::dialogsImgSkip); } - QRect tr(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, namewidth, st::dlgFont->height); - p.setFont(st::dlgHistFont->f); - p.setPen(st::dlgTextColor->p); - p.drawText(tr.left(), tr.top() + st::dlgHistFont->ascent, st::dlgHistFont->elided(lang((_searchInPeer->isChannel() && !_searchInPeer->isMegagroup()) ? lng_dlg_search_channel : lng_dlg_search_chat), tr.width())); + QRect tr(nameleft, st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip, namewidth, st::dialogsTextFont->height); + p.setFont(st::dialogsTextFont); + p.setPen(st::dialogsTextFg); + p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided(lang((_searchInPeer->isChannel() && !_searchInPeer->isMegagroup()) ? lng_dlg_search_channel : lng_dlg_search_chat), tr.width())); - p.setPen(st::dlgNameColor->p); + p.setPen(st::dialogsNameFg); _searchInPeer->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); } @@ -332,7 +333,7 @@ void DialogsInner::onUpdateSelected(bool force) { if (_state == DefaultState) { auto newImportantSwitchSel = (importantDialogs && mouseY >= 0 && mouseY < dialogsOffset()); mouseY -= dialogsOffset(); - auto newSel = newImportantSwitchSel ? nullptr : shownDialogs()->rowAtY(mouseY, st::dlgHeight); + auto newSel = newImportantSwitchSel ? nullptr : shownDialogs()->rowAtY(mouseY, st::dialogsRowHeight); if (newSel != _sel || newImportantSwitchSel != _importantSwitchSel) { updateSelectedRow(); _sel = newSel; @@ -357,7 +358,7 @@ void DialogsInner::onUpdateSelected(bool force) { } } if (!_filterResults.isEmpty()) { - int32 skip = filteredOffset(), newFilteredSel = (mouseY >= skip) ? ((mouseY - skip) / int32(st::dlgHeight)) : -1; + int32 skip = filteredOffset(), newFilteredSel = (mouseY >= skip) ? ((mouseY - skip) / int32(st::dialogsRowHeight)) : -1; if (newFilteredSel < 0 || newFilteredSel >= _filterResults.size()) { newFilteredSel = -1; } @@ -369,7 +370,7 @@ void DialogsInner::onUpdateSelected(bool force) { } } if (!_peopleResults.isEmpty()) { - int32 skip = peopleOffset(), newPeopleSel = (mouseY >= skip) ? ((mouseY - skip) / int32(st::dlgHeight)) : -1; + int32 skip = peopleOffset(), newPeopleSel = (mouseY >= skip) ? ((mouseY - skip) / int32(st::dialogsRowHeight)) : -1; if (newPeopleSel < 0 || newPeopleSel >= _peopleResults.size()) { newPeopleSel = -1; } @@ -381,7 +382,7 @@ void DialogsInner::onUpdateSelected(bool force) { } } if (_state == SearchedState && !_searchResults.isEmpty()) { - int32 skip = searchedOffset(), newSearchedSel = (mouseY >= skip) ? ((mouseY - skip) / int32(st::dlgHeight)) : -1; + int32 skip = searchedOffset(), newSearchedSel = (mouseY >= skip) ? ((mouseY - skip) / int32(st::dialogsRowHeight)) : -1; if (newSearchedSel < 0 || newSearchedSel >= _searchResults.size()) { newSearchedSel = -1; } @@ -406,7 +407,7 @@ void DialogsInner::mousePressEvent(QMouseEvent *e) { void DialogsInner::resizeEvent(QResizeEvent *e) { _addContactLnk.move((width() - _addContactLnk.width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2); - _cancelSearchInPeer.move(width() - st::dlgPaddingHor - st::btnCancelSearch.width, (st::dlgHeight - st::btnCancelSearch.height) / 2); + _cancelSearchInPeer.move(width() - st::dialogsPadding.x() - st::btnCancelSearch.width, (st::dialogsRowHeight - st::btnCancelSearch.height) / 2); } void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) { @@ -457,14 +458,14 @@ void DialogsInner::createDialog(History *history) { } } - int from = dialogsOffset() + changed.movedFrom * st::dlgHeight; - int to = dialogsOffset() + changed.movedTo * st::dlgHeight; + int from = dialogsOffset() + changed.movedFrom * st::dialogsRowHeight; + int to = dialogsOffset() + changed.movedTo * st::dialogsRowHeight; emit dialogMoved(from, to); if (creating) { refresh(); } else if (_state == DefaultState && changed.movedFrom != changed.movedTo) { - update(0, qMin(from, to), fullWidth(), qAbs(from - to) + st::dlgHeight); + update(0, qMin(from, to), fullWidth(), qAbs(from - to) + st::dialogsRowHeight); } } @@ -498,13 +499,13 @@ void DialogsInner::removeDialog(History *history) { void DialogsInner::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) { if (_state == DefaultState) { if (Global::DialogsMode() == list) { - update(0, dialogsOffset() + row->pos() * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, dialogsOffset() + row->pos() * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); } } else if (_state == FilteredState || _state == SearchedState) { if (list == Dialogs::Mode::All) { for (int32 i = 0, l = _filterResults.size(); i < l; ++i) { if (_filterResults.at(i)->history() == row->history()) { - update(0, i * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, i * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); break; } } @@ -515,13 +516,13 @@ void DialogsInner::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) { void DialogsInner::dlgUpdated(History *history, MsgId msgId) { if (_state == DefaultState) { if (auto row = shownDialogs()->getRow(history->peer->id)) { - update(0, dialogsOffset() + row->pos() * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, dialogsOffset() + row->pos() * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); } } else if (_state == FilteredState || _state == SearchedState) { int32 cnt = 0, add = filteredOffset(); for (FilteredDialogs::const_iterator i = _filterResults.cbegin(), e = _filterResults.cend(); i != e; ++i) { if ((*i)->history() == history) { - update(0, add + cnt * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, add + cnt * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); break; } ++cnt; @@ -530,7 +531,7 @@ void DialogsInner::dlgUpdated(History *history, MsgId msgId) { int32 cnt = 0, add = peopleOffset(); for (PeopleResults::const_iterator i = _peopleResults.cbegin(), e = _peopleResults.cend(); i != e; ++i) { if ((*i) == history->peer) { - update(0, add + cnt * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, add + cnt * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); break; } ++cnt; @@ -540,7 +541,7 @@ void DialogsInner::dlgUpdated(History *history, MsgId msgId) { int32 cnt = 0, add = searchedOffset(); for (SearchResults::const_iterator i = _searchResults.cbegin(), e = _searchResults.cend(); i != e; ++i) { if ((*i)->item()->history() == history && (*i)->item()->id == msgId) { - update(0, add + cnt * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, add + cnt * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); break; } ++cnt; @@ -560,30 +561,30 @@ void DialogsInner::updateSelectedRow(PeerData *peer) { if (peer) { if (History *h = App::historyLoaded(peer->id)) { if (h->inChatList(Global::DialogsMode())) { - update(0, dialogsOffset() + h->posInChatList(Global::DialogsMode()) * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, dialogsOffset() + h->posInChatList(Global::DialogsMode()) * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); } } } else if (_sel) { - update(0, dialogsOffset() + _sel->pos() * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, dialogsOffset() + _sel->pos() * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); } else if (_importantSwitchSel) { - update(0, 0, fullWidth(), st::dlgImportantHeight); + update(0, 0, fullWidth(), st::dialogsImportantBarHeight); } } else if (_state == FilteredState || _state == SearchedState) { if (peer) { for (int32 i = 0, l = _filterResults.size(); i != l; ++i) { if (_filterResults.at(i)->history()->peer == peer) { - update(0, filteredOffset() + i * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, filteredOffset() + i * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); break; } } } else if (_hashtagSel >= 0) { update(0, _hashtagSel * st::mentionHeight, fullWidth(), st::mentionHeight); } else if (_filteredSel >= 0) { - update(0, filteredOffset() + _filteredSel * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, filteredOffset() + _filteredSel * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); } else if (_peopleSel >= 0) { - update(0, peopleOffset() + _peopleSel * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, peopleOffset() + _peopleSel * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); } else if (_searchedSel >= 0) { - update(0, searchedOffset() + _searchedSel * st::dlgHeight, fullWidth(), st::dlgHeight); + update(0, searchedOffset() + _searchedSel * st::dialogsRowHeight, fullWidth(), st::dialogsRowHeight); } } @@ -1156,14 +1157,14 @@ void DialogsInner::notify_historyMuteUpdated(History *history) { return; } - int from = dialogsOffset() + changed.movedFrom * st::dlgHeight; - int to = dialogsOffset() + changed.movedTo * st::dlgHeight; + int from = dialogsOffset() + changed.movedFrom * st::dialogsRowHeight; + int to = dialogsOffset() + changed.movedTo * st::dialogsRowHeight; emit dialogMoved(from, to); if (creating) { refresh(); } else if (_state == DefaultState && changed.movedFrom != changed.movedTo) { - update(0, qMin(from, to), fullWidth(), qAbs(from - to) + st::dlgHeight); + update(0, qMin(from, to), fullWidth(), qAbs(from - to) + st::dialogsRowHeight); } } } @@ -1179,15 +1180,15 @@ void DialogsInner::refresh(bool toTop) { if (!_addContactLnk.isHidden()) _addContactLnk.hide(); } } else { - h = dialogsOffset() + shownDialogs()->size() * st::dlgHeight; + h = dialogsOffset() + shownDialogs()->size() * st::dialogsRowHeight; if (!_addContactLnk.isHidden()) _addContactLnk.hide(); } } else { if (!_addContactLnk.isHidden()) _addContactLnk.hide(); if (_state == FilteredState) { - h = searchedOffset() + (_searchResults.count() * st::dlgHeight) + ((_searchResults.isEmpty() && !_searchInPeer) ? -st::searchedBarHeight : 0); + h = searchedOffset() + (_searchResults.count() * st::dialogsRowHeight) + ((_searchResults.isEmpty() && !_searchInPeer) ? -st::searchedBarHeight : 0); } else if (_state == SearchedState) { - h = searchedOffset() + (_searchResults.count() * st::dlgHeight); + h = searchedOffset() + (_searchResults.count() * st::dialogsRowHeight); } } setHeight(h); @@ -1295,8 +1296,8 @@ void DialogsInner::selectSkip(int32 direction) { } } if (_importantSwitchSel || _sel) { - int fromY = _importantSwitchSel ? 0 : (dialogsOffset() + _sel->pos() * st::dlgHeight); - emit mustScrollTo(fromY, fromY + st::dlgHeight); + int fromY = _importantSwitchSel ? 0 : (dialogsOffset() + _sel->pos() * st::dialogsRowHeight); + emit mustScrollTo(fromY, fromY + st::dialogsRowHeight); } } else if (_state == FilteredState || _state == SearchedState) { if (_hashtagResults.isEmpty() && _filterResults.isEmpty() && _peopleResults.isEmpty() && _searchResults.isEmpty()) return; @@ -1333,11 +1334,11 @@ void DialogsInner::selectSkip(int32 direction) { if (_hashtagSel >= 0 && _hashtagSel < _hashtagResults.size()) { emit mustScrollTo(_hashtagSel * st::mentionHeight, (_hashtagSel + 1) * st::mentionHeight); } else if (_filteredSel >= 0 && _filteredSel < _filterResults.size()) { - emit mustScrollTo(filteredOffset() + _filteredSel * st::dlgHeight, filteredOffset() + (_filteredSel + 1) * st::dlgHeight); + emit mustScrollTo(filteredOffset() + _filteredSel * st::dialogsRowHeight, filteredOffset() + (_filteredSel + 1) * st::dialogsRowHeight); } else if (_peopleSel >= 0 && _peopleSel < _peopleResults.size()) { - emit mustScrollTo(peopleOffset() + _peopleSel * st::dlgHeight + (_peopleSel ? 0 : -st::searchedBarHeight), peopleOffset() + (_peopleSel + 1) * st::dlgHeight); + emit mustScrollTo(peopleOffset() + _peopleSel * st::dialogsRowHeight + (_peopleSel ? 0 : -st::searchedBarHeight), peopleOffset() + (_peopleSel + 1) * st::dialogsRowHeight); } else { - emit mustScrollTo(searchedOffset() + _searchedSel * st::dlgHeight + (_searchedSel ? 0 : -st::searchedBarHeight), searchedOffset() + (_searchedSel + 1) * st::dlgHeight); + emit mustScrollTo(searchedOffset() + _searchedSel * st::dialogsRowHeight + (_searchedSel ? 0 : -st::searchedBarHeight), searchedOffset() + (_searchedSel + 1) * st::dialogsRowHeight); } } update(); @@ -1347,13 +1348,13 @@ void DialogsInner::scrollToPeer(const PeerId &peer, MsgId msgId) { int32 fromY = -1; if (_state == DefaultState) { if (auto row = shownDialogs()->getRow(peer)) { - fromY = dialogsOffset() + row->pos() * st::dlgHeight; + fromY = dialogsOffset() + row->pos() * st::dialogsRowHeight; } } else if (_state == FilteredState || _state == SearchedState) { if (msgId) { for (int32 i = 0, c = _searchResults.size(); i < c; ++i) { if (_searchResults[i]->item()->history()->peer->id == peer && _searchResults[i]->item()->id == msgId) { - fromY = searchedOffset() + i * st::dlgHeight; + fromY = searchedOffset() + i * st::dialogsRowHeight; break; } } @@ -1361,19 +1362,19 @@ void DialogsInner::scrollToPeer(const PeerId &peer, MsgId msgId) { if (fromY < 0) { for (int32 i = 0, c = _filterResults.size(); i < c; ++i) { if (_filterResults[i]->history()->peer->id == peer) { - fromY = filteredOffset() + (i * st::dlgHeight); + fromY = filteredOffset() + (i * st::dialogsRowHeight); break; } } } } if (fromY >= 0) { - emit mustScrollTo(fromY, fromY + st::dlgHeight); + emit mustScrollTo(fromY, fromY + st::dialogsRowHeight); } } void DialogsInner::selectSkipPage(int32 pixels, int32 direction) { - int toSkip = pixels / int(st::dlgHeight); + int toSkip = pixels / int(st::dialogsRowHeight); if (_state == DefaultState) { if (!_sel) { if (direction > 0 && !shownDialogs()->isEmpty()) { @@ -1397,8 +1398,8 @@ void DialogsInner::selectSkipPage(int32 pixels, int32 direction) { } } if (_importantSwitchSel || _sel) { - int fromY = (_importantSwitchSel ? 0 : (dialogsOffset() + _sel->pos() * st::dlgHeight)); - emit mustScrollTo(fromY, fromY + st::dlgHeight); + int fromY = (_importantSwitchSel ? 0 : (dialogsOffset() + _sel->pos() * st::dialogsRowHeight)); + emit mustScrollTo(fromY, fromY + st::dialogsRowHeight); } } else { return selectSkip(direction * toSkip); @@ -1412,10 +1413,10 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { int32 yTo = yFrom + parentWidget()->height() * 5; MTP::clearLoaderPriorities(); if (_state == DefaultState) { - int32 otherStart = shownDialogs()->size() * st::dlgHeight; + int32 otherStart = shownDialogs()->size() * st::dialogsRowHeight; if (yFrom < otherStart) { - for (auto i = shownDialogs()->cfind(yFrom, st::dlgHeight), end = shownDialogs()->cend(); i != end; ++i) { - if (((*i)->pos() * st::dlgHeight) >= yTo) { + for (auto i = shownDialogs()->cfind(yFrom, st::dialogsRowHeight), end = shownDialogs()->cend(); i != end; ++i) { + if (((*i)->pos() * st::dialogsRowHeight) >= yTo) { break; } (*i)->history()->peer->loadUserpic(); @@ -1426,10 +1427,10 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { } yTo -= otherStart; } else if (_state == FilteredState || _state == SearchedState) { - int32 from = (yFrom - filteredOffset()) / st::dlgHeight; + int32 from = (yFrom - filteredOffset()) / st::dialogsRowHeight; if (from < 0) from = 0; if (from < _filterResults.size()) { - int32 to = (yTo / int32(st::dlgHeight)) + 1, w = width(); + int32 to = (yTo / int32(st::dialogsRowHeight)) + 1, w = width(); if (to > _filterResults.size()) to = _filterResults.size(); for (; from < to; ++from) { @@ -1437,20 +1438,20 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { } } - from = (yFrom > filteredOffset() + st::searchedBarHeight ? ((yFrom - filteredOffset() - st::searchedBarHeight) / int32(st::dlgHeight)) : 0) - _filterResults.size(); + from = (yFrom > filteredOffset() + st::searchedBarHeight ? ((yFrom - filteredOffset() - st::searchedBarHeight) / int32(st::dialogsRowHeight)) : 0) - _filterResults.size(); if (from < 0) from = 0; if (from < _peopleResults.size()) { - int32 to = (yTo > filteredOffset() + st::searchedBarHeight ? ((yTo - filteredOffset() - st::searchedBarHeight) / int32(st::dlgHeight)) : 0) - _filterResults.size() + 1, w = width(); + int32 to = (yTo > filteredOffset() + st::searchedBarHeight ? ((yTo - filteredOffset() - st::searchedBarHeight) / int32(st::dialogsRowHeight)) : 0) - _filterResults.size() + 1, w = width(); if (to > _peopleResults.size()) to = _peopleResults.size(); for (; from < to; ++from) { _peopleResults[from]->loadUserpic(); } } - from = (yFrom > filteredOffset() + ((_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight) ? ((yFrom - filteredOffset() - (_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(st::dlgHeight)) : 0) - _filterResults.size() - _peopleResults.size(); + from = (yFrom > filteredOffset() + ((_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight) ? ((yFrom - filteredOffset() - (_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(st::dialogsRowHeight)) : 0) - _filterResults.size() - _peopleResults.size(); if (from < 0) from = 0; if (from < _searchResults.size()) { - int32 to = (yTo > filteredOffset() + (_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight ? ((yTo - filteredOffset() - (_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(st::dlgHeight)) : 0) - _filterResults.size() - _peopleResults.size() + 1, w = width(); + int32 to = (yTo > filteredOffset() + (_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight ? ((yTo - filteredOffset() - (_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(st::dialogsRowHeight)) : 0) - _filterResults.size() - _peopleResults.size() + 1, w = width(); if (to > _searchResults.size()) to = _searchResults.size(); for (; from < to; ++from) { @@ -1761,7 +1762,7 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : TWidget(parent) , _newGroup(this, st::btnNewGroup) , _addContact(this, st::btnAddContact) , _cancelSearch(this, st::btnCancelSearch) -, _scroll(this, st::dlgScroll) +, _scroll(this, st::dialogsScroll) , _inner(&_scroll, parent) , _a_show(animation(this, &DialogsWidget::step_show)) , _searchInPeer(0) @@ -1800,15 +1801,15 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : TWidget(parent) _scroll.show(); _filter.show(); - _filter.move(st::dlgPaddingHor, st::dlgFilterPadding); + _filter.move(st::dialogsPadding.x(), st::dialogsFilterPadding); _filter.setFocusPolicy(Qt::StrongFocus); _filter.customUpDown(true); _addContact.hide(); _newGroup.show(); _cancelSearch.hide(); - _newGroup.move(width() - _newGroup.width() - st::dlgPaddingHor, 0); - _addContact.move(width() - _addContact.width() - st::dlgPaddingHor, 0); - _cancelSearch.move(width() - _cancelSearch.width() - st::dlgPaddingHor, 0); + _newGroup.move(width() - _newGroup.width() - st::dialogsPadding.x(), 0); + _addContact.move(width() - _addContact.width() - st::dialogsPadding.x(), 0); + _cancelSearch.move(width() - _cancelSearch.width() - st::dialogsPadding.x(), 0); } void DialogsWidget::activate() { @@ -2342,10 +2343,10 @@ void DialogsWidget::onListScroll() { _inner.loadPeerPhotos(_scroll.scrollTop()); if (_inner.state() == DialogsInner::SearchedState || (_inner.state() == DialogsInner::FilteredState && _searchInMigrated && _searchFull && !_searchFullMigrated)) { - if (_scroll.scrollTop() > (_inner.searchList().size() + _inner.filteredList().size() + _inner.peopleList().size()) * st::dlgHeight - PreloadHeightsCount * _scroll.height()) { + if (_scroll.scrollTop() > (_inner.searchList().size() + _inner.filteredList().size() + _inner.peopleList().size()) * st::dialogsRowHeight - PreloadHeightsCount * _scroll.height()) { onSearchMore(); } - } else if (_scroll.scrollTop() > _inner.dialogsList()->size() * st::dlgHeight - PreloadHeightsCount * _scroll.height()) { + } else if (_scroll.scrollTop() > _inner.dialogsList()->size() * st::dialogsRowHeight - PreloadHeightsCount * _scroll.height()) { loadDialogs(); } } @@ -2425,15 +2426,15 @@ void DialogsWidget::onCompleteHashtag(QString tag) { void DialogsWidget::resizeEvent(QResizeEvent *e) { int32 w = width(); - _filter.setGeometry(st::dlgPaddingHor, st::dlgFilterPadding, w - 2 * st::dlgPaddingHor, _filter.height()); - _newGroup.move(w - _newGroup.width() - st::dlgPaddingHor, _filter.y()); - _addContact.move(w - _addContact.width() - st::dlgPaddingHor, _filter.y()); - _cancelSearch.move(w - _cancelSearch.width() - st::dlgPaddingHor, _filter.y()); - _scroll.move(0, _filter.height() + 2 * st::dlgFilterPadding); + _filter.setGeometry(st::dialogsPadding.x(), st::dialogsFilterPadding, w - 2 * st::dialogsPadding.x(), _filter.height()); + _newGroup.move(w - _newGroup.width() - st::dialogsPadding.x(), _filter.y()); + _addContact.move(w - _addContact.width() - st::dialogsPadding.x(), _filter.y()); + _cancelSearch.move(w - _cancelSearch.width() - st::dialogsPadding.x(), _filter.y()); + _scroll.move(0, _filter.height() + 2 * st::dialogsFilterPadding); int32 addToY = App::main() ? App::main()->contentScrollAddToY() : 0; int32 newScrollY = _scroll.scrollTop() + addToY; - _scroll.resize(w, height() - _filter.y() - _filter.height() - st::dlgFilterPadding - st::dlgPaddingVer); + _scroll.resize(w, height() - _filter.y() - _filter.height() - st::dialogsFilterPadding - st::dialogsPadding.y()); if (addToY) { _scroll.scrollToY(newScrollY); } else { @@ -2583,6 +2584,6 @@ void DialogsWidget::onCancelSearchInPeer() { void DialogsWidget::onDialogMoved(int movedFrom, int movedTo) { int32 st = _scroll.scrollTop(); if (st > movedTo && st < movedFrom) { - _scroll.scrollToY(st + st::dlgHeight); + _scroll.scrollToY(st + st::dialogsRowHeight); } } diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 5480af8d4..21ab5d2af 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -95,6 +95,8 @@ void activateBotCommand(const HistoryItem *msg, int row, int col) { auto getMessageBot = [msg]() -> UserData* { if (auto bot = msg->viaBot()) { return bot; + } else if (auto bot = msg->from()->asUser()) { + return bot; } else if (auto bot = msg->history()->peer->asUser()) { return bot; } diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 5a8816cd7..5baf02f92 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "core/click_handler_types.h" #include "dialogs/dialogs_indexed_list.h" +#include "styles/style_dialogs.h" #include "lang.h" #include "mainwidget.h" #include "application.h" @@ -73,7 +74,7 @@ TextParseOptions _instagramDescriptionOptions = { inline void _initTextOptions() { _historySrvOptions.dir = _textNameOptions.dir = _textDlgOptions.dir = cLangDir(); - _textDlgOptions.maxw = st::dlgMaxWidth * 2; + _textDlgOptions.maxw = st::dialogsWidthMax * 2; _webpageTitleOptions.maxw = st::msgMaxWidth - st::msgPadding.left() - st::msgPadding.right() - st::webPageLeft; _webpageTitleOptions.maxh = st::webPageTitleFont->height * 2; _webpageDescriptionOptions.maxw = st::msgMaxWidth - st::msgPadding.left() - st::msgPadding.right() - st::webPageLeft; @@ -129,6 +130,9 @@ void historyInit() { History::History(const PeerId &peerId) : peer(App::peer(peerId)) +, lastItemTextCache(st::dialogsTextWidthMin) +, typingText(st::dialogsTextWidthMin) +, cloudDraftTextCache(st::dialogsTextWidthMin) , _mute(isNotifyMuted(peer->notify)) { if (peer->isUser() && peer->asUser()->botInfo) { outboxReadBefore = INT_MAX; @@ -259,7 +263,7 @@ bool History::updateTyping(uint64 ms, bool force) { newTypingStr += qsl("..."); } if (typingStr != newTypingStr) { - typingText.setText(st::dlgHistFont, (typingStr = newTypingStr), _textNameOptions); + typingText.setText(st::dialogsTextFont, (typingStr = newTypingStr), _textNameOptions); } } if (!typingStr.isEmpty()) { @@ -7494,13 +7498,6 @@ HistoryTextState HistoryMessage::getState(int x, int y, HistoryStateRequest requ } trect.setTop(trect.top() + fwdheight); } - if (via && !displayFromName() && !displayForwardedFrom()) { - if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via->_width) { - result.link = via->_lnk; - return result; - } - trect.setTop(trect.top() + st::msgNameFont->height); - } if (reply) { int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); if (y >= trect.top() && y < trect.top() + h) { @@ -7511,6 +7508,13 @@ HistoryTextState HistoryMessage::getState(int x, int y, HistoryStateRequest requ } trect.setTop(trect.top() + h); } + if (via && !displayFromName() && !displayForwardedFrom()) { + if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via->_width) { + result.link = via->_lnk; + return result; + } + trect.setTop(trect.top() + st::msgNameFont->height); + } bool inDate = false, mediaDisplayed = _media && _media->isDisplayed(); if (!mediaDisplayed || !_media->customInfoLayout()) { @@ -7568,16 +7572,16 @@ void HistoryMessage::drawInDialog(Painter &p, const QRect &r, bool act, const Hi TextCustomTagsMap custom; custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink())); msg = lng_message_with_from(lt_from, textRichPrepare((author() == App::self()) ? lang(lng_from_you) : author()->shortName()), lt_message, textRichPrepare(msg)); - cache.setRichText(st::dlgHistFont, msg, _textDlgOptions, custom); + cache.setRichText(st::dialogsTextFont, msg, _textDlgOptions, custom); } else { - cache.setText(st::dlgHistFont, msg, _textDlgOptions); + cache.setText(st::dialogsTextFont, msg, _textDlgOptions); } } if (r.width()) { - textstyleSet(&(act ? st::dlgActiveTextStyle : st::dlgTextStyle)); - p.setFont(st::dlgHistFont->f); - p.setPen((act ? st::dlgActiveColor : (emptyText() ? st::dlgSystemColor : st::dlgTextColor))->p); - cache.drawElided(p, r.left(), r.top(), r.width(), r.height() / st::dlgHistFont->height); + textstyleSet(&(act ? st::dialogsTextStyleActive : st::dialogsTextStyle)); + p.setFont(st::dialogsTextFont); + p.setPen(act ? st::dialogsTextFgActive : (emptyText() ? st::dialogsTextFgService : st::dialogsTextFg)); + cache.drawElided(p, r.left(), r.top(), r.width(), r.height() / st::dialogsTextFont->height); textstyleRestore(); } } @@ -8087,11 +8091,11 @@ HistoryTextState HistoryService::getState(int x, int y, HistoryStateRequest requ void HistoryService::drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { if (cacheFor != this) { cacheFor = this; - cache.setText(st::dlgHistFont, inDialogsText(), _textDlgOptions); + cache.setText(st::dialogsTextFont, inDialogsText(), _textDlgOptions); } QRect tr(r); - p.setPen((act ? st::dlgActiveColor : st::dlgSystemColor)->p); - cache.drawElided(p, tr.left(), tr.top(), tr.width(), tr.height() / st::dlgHistFont->height); + p.setPen(act ? st::dialogsTextFgActive : st::dialogsTextFgService); + cache.drawElided(p, tr.left(), tr.top(), tr.width(), tr.height() / st::dialogsTextFont->height); } QString HistoryService::notificationText() const { diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 8582334c7..0508473ad 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -458,14 +458,14 @@ public: mtpRequestId sendRequestId = 0; mutable const HistoryItem *textCachedFor = nullptr; // cache - mutable Text lastItemTextCache = Text{ int(st::dlgRichMinWidth) }; + mutable Text lastItemTextCache; typedef QMap TypingUsers; TypingUsers typing; typedef QMap SendActionUsers; SendActionUsers sendActions; QString typingStr; - Text typingText = Text{ int(st::dlgRichMinWidth) }; + Text typingText; uint32 typingDots; QMap mySendActions; @@ -504,7 +504,7 @@ public: void changeMsgId(MsgId oldId, MsgId newId); - Text cloudDraftTextCache = Text { int(st::dlgRichMinWidth) }; + Text cloudDraftTextCache; protected: diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index a423edf68..756007d45 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "historywidget.h" #include "styles/style_history.h" +#include "styles/style_dialogs.h" #include "boxes/confirmbox.h" #include "boxes/photosendbox.h" #include "ui/filedialog.h" @@ -1552,6 +1553,15 @@ HistoryInner::~HistoryInner() { _dragAction = NoDrag; } +bool HistoryInner::focusNextPrevChild(bool next) { + if (_selected.isEmpty()) { + return focusNextPrevChild(next); + } else { + clearSelectedItems(); + return true; + } +} + void HistoryInner::adjustCurrent(int32 y) const { int32 htop = historyTop(), hdrawtop = historyDrawTop(), mtop = migratedTop(); _curHistory = 0; @@ -3036,13 +3046,15 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) { } void HistoryWidget::updateStickersByEmoji() { - int32 len = 0; - auto &text = _field.getTextWithTags().text; - if (EmojiPtr emoji = emojiFromText(text, &len)) { - if (text.size() > len) { - len = 0; - } else { - _fieldAutocomplete->showStickers(emoji); + int len = 0; + if (!_editMsgId) { + auto &text = _field.getTextWithTags().text; + if (auto emoji = emojiFromText(text, &len)) { + if (text.size() > len) { + len = 0; + } else { + _fieldAutocomplete->showStickers(emoji); + } } } if (!len) { @@ -3187,7 +3199,7 @@ void HistoryWidget::writeDrafts(HistoryDraft **localDraft, HistoryDraft **editDr } if (!_editMsgId) { - _saveCloudDraftTimer.start(SaveCloudDraftTimeout); + _saveCloudDraftTimer.start(SaveCloudDraftIdleTimeout); } } @@ -4906,7 +4918,10 @@ bool HistoryWidget::joinFail(const RPCError &error, mtpRequestId req) { if (error.type() == qstr("CHANNEL_PRIVATE") || error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA") || error.type() == qstr("USER_BANNED_IN_CHANNEL")) { Ui::showLayer(new InformBox(lang((_peer && _peer->isMegagroup()) ? lng_group_not_accessible : lng_channel_not_accessible))); return true; + } else if (error.type() == qstr("CHANNELS_TOO_MUCH")) { + Ui::showLayer(new InformBox(lang(lng_join_channel_error))); } + return false; } @@ -5801,16 +5816,16 @@ void HistoryWidget::paintTopBar(Painter &p, float64 over, int32 decreaseWidth) { int32 increaseLeft = Adaptive::OneColumn() ? (st::topBarForwardPadding.right() - st::topBarForwardPadding.left()) : 0; decreaseWidth += increaseLeft; QRect rectForName(st::topBarForwardPadding.left() + increaseLeft, st::topBarForwardPadding.top(), width() - decreaseWidth - st::topBarForwardPadding.left() - st::topBarForwardPadding.right(), st::msgNameFont->height); - p.setFont(st::dlgHistFont->f); + p.setFont(st::dialogsTextFont); if (_history->typing.isEmpty() && _history->sendActions.isEmpty()) { p.setPen(st::titleStatusColor->p); - p.drawText(rectForName.x(), st::topBarHeight - st::topBarForwardPadding.bottom() - st::dlgHistFont->height + st::dlgHistFont->ascent, _titlePeerText); + p.drawText(rectForName.x(), st::topBarHeight - st::topBarForwardPadding.bottom() - st::dialogsTextFont->height + st::dialogsTextFont->ascent, _titlePeerText); } else { p.setPen(st::titleTypingColor->p); - _history->typingText.drawElided(p, rectForName.x(), st::topBarHeight - st::topBarForwardPadding.bottom() - st::dlgHistFont->height, rectForName.width()); + _history->typingText.drawElided(p, rectForName.x(), st::topBarHeight - st::topBarForwardPadding.bottom() - st::dialogsTextFont->height, rectForName.width()); } - p.setPen(st::dlgNameColor->p); + p.setPen(st::dialogsNameFg); _peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); if (Adaptive::OneColumn()) { @@ -5882,7 +5897,7 @@ void HistoryWidget::updateOnlineDisplay(int32 x, int32 w) { } if (_titlePeerText != text) { _titlePeerText = text; - _titlePeerTextWidth = st::dlgHistFont->width(_titlePeerText); + _titlePeerTextWidth = st::dialogsTextFont->width(_titlePeerText); if (App::main()) { App::main()->topBar()->update(); } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 490651c18..2847bf694 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -115,6 +115,9 @@ public: ~HistoryInner(); +protected: + bool focusNextPrevChild(bool next) override; + public slots: void onUpdateSelected(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index a69a663af..aa1c15cff 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -21,7 +21,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "mainwidget.h" +#include "styles/style_dialogs.h" #include "ui/buttons/peer_avatar_button.h" +#include "ui/buttons/round_button.h" #include "window/section_memento.h" #include "window/section_widget.h" #include "window/top_bar_widget.h" @@ -56,6 +58,7 @@ StackItemSection::~StackItemSection() { MainWidget::MainWidget(MainWindow *window) : TWidget(window) , _a_show(animation(this, &MainWidget::step_show)) +, _dialogsWidth(st::dialogsWidthMin) , _sideShadow(this, st::shadowColor) , _dialogs(this) , _history(this) @@ -2526,8 +2529,8 @@ void MainWidget::showAll() { cSetPasswordRecovered(false); Ui::showLayer(new InformBox(lang(lng_signin_password_removed))); } - _sideShadow.show(); if (Adaptive::OneColumn()) { + _sideShadow.hide(); if (_hider) { _hider->hide(); if (!_forwardConfirm && _hider->wasOffered()) { @@ -2562,6 +2565,7 @@ void MainWidget::showAll() { _dialogs->hide(); } } else { + _sideShadow.show(); if (_hider) { _hider->show(); if (_forwardConfirm) { @@ -2593,6 +2597,14 @@ void MainWidget::showAll() { App::wnd()->checkHistoryActivation(); } +namespace { + +inline int chatsListWidth(int windowWidth) { + return snap((windowWidth * 5) / 14, st::dialogsWidthMin, st::dialogsWidthMax); +} + +} // namespace + void MainWidget::resizeEvent(QResizeEvent *e) { int32 tbh = _topBar->isHidden() ? 0 : st::topBarHeight; if (Adaptive::OneColumn()) { @@ -3451,9 +3463,12 @@ void MainWidget::inviteImportDone(const MTPUpdates &updates) { bool MainWidget::inviteImportFail(const RPCError &error) { if (MTP::isDefaultHandledError(error)) return false; - if (error.code() == 400) { + if (error.type() == qstr("CHANNELS_TOO_MUCH")) { + Ui::showLayer(new InformBox(lang(lng_join_channel_error))); + } else if (error.code() == 400) { Ui::showLayer(new InformBox(lang(error.type() == qstr("USERS_TOO_MUCH") ? lng_group_invite_no_room : lng_group_invite_bad_link))); } + return true; } @@ -3761,24 +3776,7 @@ void MainWidget::saveDraftToCloud() { auto localDraft = history->localDraft(); auto cloudDraft = history->cloudDraft(); if (!historyDraftsAreEqual(localDraft, cloudDraft)) { - if (cloudDraft && cloudDraft->saveRequestId) { - MTP::cancel(cloudDraft->saveRequestId); - } - cloudDraft = history->createCloudDraft(localDraft); - - MTPmessages_SaveDraft::Flags flags = 0; - auto &textWithTags = cloudDraft->textWithTags; - if (cloudDraft->previewCancelled) { - flags |= MTPmessages_SaveDraft::Flag::f_no_webpage; - } - if (cloudDraft->msgId) { - flags |= MTPmessages_SaveDraft::Flag::f_reply_to_msg_id; - } - if (!textWithTags.tags.isEmpty()) { - flags |= MTPmessages_SaveDraft::Flag::f_entities; - } - auto entities = linksToMTP(entitiesFromTextTags(textWithTags.tags), true); - cloudDraft->saveRequestId = MTP::send(MTPmessages_SaveDraft(MTP_flags(flags), MTP_int(cloudDraft->msgId), peer->input, MTP_string(textWithTags.text), entities), rpcDone(&MainWidget::saveCloudDraftDone, peer), rpcFail(&MainWidget::saveCloudDraftFail, peer)); + App::api()->saveDraftToCloudDelayed(history); } } } @@ -3787,30 +3785,6 @@ void MainWidget::applyCloudDraft(History *history) { _history->applyCloudDraft(history); } -void MainWidget::saveCloudDraftDone(PeerData *peer, const MTPBool &result, mtpRequestId requestId) { - if (auto history = App::historyLoaded(peer)) { - if (auto cloudDraft = history->cloudDraft()) { - if (cloudDraft->saveRequestId == requestId) { - cloudDraft->saveRequestId = 0; - history->updateChatListEntry(); - } - } - } -} - -bool MainWidget::saveCloudDraftFail(PeerData *peer, const RPCError &error, mtpRequestId requestId) { - if (MTP::isDefaultHandledError(error)) return false; - - if (auto history = App::historyLoaded(peer)) { - if (auto cloudDraft = history->cloudDraft()) { - if (cloudDraft->saveRequestId == requestId) { - history->clearCloudDraft(); - } - } - } - return true; -} - void MainWidget::checkIdleFinish() { if (this != App::main()) return; if (psIdleTime() < uint64(Global::OfflineIdleTimeout())) { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index d611867c7..8348fd2e6 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -129,10 +129,6 @@ public: } }; -inline int chatsListWidth(int windowWidth) { - return snap((windowWidth * 5) / 14, st::dlgMinWidth, st::dlgMaxWidth); -} - enum SilentNotifiesStatus { SilentNotifiesDontChange, SilentNotifiesSetSilent, @@ -503,9 +499,6 @@ private: void messagesAffected(PeerData *peer, const MTPmessages_AffectedMessages &result); void overviewLoaded(History *history, const MTPmessages_Messages &result, mtpRequestId req); - void saveCloudDraftDone(PeerData *peer, const MTPBool &result, mtpRequestId requestId); - bool saveCloudDraftFail(PeerData *peer, const RPCError &error, mtpRequestId requestId); - Window::SectionSlideParams prepareShowAnimation(bool willHaveTopBarShadow); void showWideSectionAnimated(const Window::SectionMemento *memento, bool back); @@ -582,7 +575,7 @@ private: anim::ivalue a_coordUnder, a_coordOver; anim::fvalue a_shadow; - int _dialogsWidth = st::dlgMinWidth; + int _dialogsWidth; PlainShadow _sideShadow; diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index c50499a6f..3cc03d30f 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "mainwindow.h" +#include "styles/style_dialogs.h" #include "zip.h" #include "lang.h" #include "shortcuts.h" @@ -182,48 +183,48 @@ void NotifyWindow::updateNotifyDisplay() { QRect rectForName(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height); if (!App::passcoded() && cNotifyView() <= dbinvShowName) { if (history->peer->isChat() || history->peer->isMegagroup()) { - p.drawSprite(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), st::dlgChatImg); - rectForName.setLeft(rectForName.left() + st::dlgImgSkip); + p.drawSprite(QPoint(rectForName.left() + st::dialogsChatImgPos.x(), rectForName.top() + st::dialogsChatImgPos.y()), st::dlgChatImg); + rectForName.setLeft(rectForName.left() + st::dialogsImgSkip); } else if (history->peer->isChannel()) { - p.drawSprite(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), st::dlgChannelImg); - rectForName.setLeft(rectForName.left() + st::dlgImgSkip); + p.drawSprite(QPoint(rectForName.left() + st::dialogsChannelImgPos.x(), rectForName.top() + st::dialogsChannelImgPos.y()), st::dlgChannelImg); + rectForName.setLeft(rectForName.left() + st::dialogsImgSkip); } } QDateTime now(QDateTime::currentDateTime()), lastTime(item->date); QDate nowDate(now.date()), lastDate(lastTime.date()); QString dt = lastTime.toString(cTimeFormat()); - int32 dtWidth = st::dlgHistFont->width(dt); - rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip); - p.setFont(st::dlgDateFont->f); - p.setPen(st::dlgDateColor->p); - p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::dlgHistFont->ascent, dt); + int32 dtWidth = st::dialogsTextFont->width(dt); + rectForName.setWidth(rectForName.width() - dtWidth - st::dialogsDateSkip); + p.setFont(st::dialogsDateFont); + p.setPen(st::dialogsDateFg); + p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::dialogsTextFont->ascent, dt); if (!App::passcoded() && cNotifyView() <= dbinvShowPreview) { const HistoryItem *textCachedFor = 0; Text itemTextCache(itemWidth); - QRect r(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dlgFont->height); + QRect r(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dialogsTextFont->height); if (fwdCount < 2) { bool active = false; item->drawInDialog(p, r, active, textCachedFor, itemTextCache); } else { - p.setFont(st::dlgHistFont->f); + p.setFont(st::dialogsTextFont); if (item->hasFromName() && !item->isPost()) { - itemTextCache.setText(st::dlgHistFont, item->author()->name); - p.setPen(st::dlgSystemColor->p); - itemTextCache.drawElided(p, r.left(), r.top(), r.width(), st::dlgHistFont->height); - r.setTop(r.top() + st::dlgHistFont->height); + itemTextCache.setText(st::dialogsTextFont, item->author()->name); + p.setPen(st::dialogsTextFgService); + itemTextCache.drawElided(p, r.left(), r.top(), r.width(), st::dialogsTextFont->height); + r.setTop(r.top() + st::dialogsTextFont->height); } - p.setPen(st::dlgTextColor->p); - p.drawText(r.left(), r.top() + st::dlgHistFont->ascent, lng_forward_messages(lt_count, fwdCount)); + p.setPen(st::dialogsTextFg); + p.drawText(r.left(), r.top() + st::dialogsTextFont->ascent, lng_forward_messages(lt_count, fwdCount)); } } else { - static QString notifyText = st::dlgHistFont->elided(lang(lng_notification_preview), itemWidth); - p.setPen(st::dlgSystemColor->p); - p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dlgHistFont->ascent, notifyText); + static QString notifyText = st::dialogsTextFont->elided(lang(lng_notification_preview), itemWidth); + p.setPen(st::dialogsTextFgService); + p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText); } - p.setPen(st::dlgNameColor->p); + p.setPen(st::dialogsNameFg); if (!App::passcoded() && cNotifyView() <= dbinvShowName) { history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); } else { @@ -1282,9 +1283,8 @@ void MainWindow::toggleDisplayNotifyFromTray() { } void MainWindow::closeEvent(QCloseEvent *e) { - if (MTP::authedId() && !Sandbox::isSavingSession() && Ui::hideWindowNoQuit()) { - e->ignore(); - } else { + e->ignore(); + if (!MTP::authedId() || Sandbox::isSavingSession() || !Ui::hideWindowNoQuit()) { App::quit(); } } diff --git a/Telegram/SourceFiles/overview/overview.style b/Telegram/SourceFiles/overview/overview.style index f300e6989..ed8e546bc 100644 --- a/Telegram/SourceFiles/overview/overview.style +++ b/Telegram/SourceFiles/overview/overview.style @@ -63,6 +63,8 @@ linksBorder: 1px; linksBorderFg: #eaeaea; linksDateColor: #808080; linksDateMargin: margins(0px, 15px, 0px, 2px); +linksPhotoSize: 46px; +linksPhotoPadding: 12px; overviewLinksCheck: icon { { "overview_links_check_bg", overviewCheckBg }, { "overview_links_check", #fff, point(4px, 5px) }, diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 42c69b4cc..64cb93cab 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -770,7 +770,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con if (selected || context->selecting) { QRect check(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::defaultCheckbox.diameter), rthumb.height() - st::defaultCheckbox.diameter), QSize(st::defaultCheckbox.diameter, st::defaultCheckbox.diameter)); p.fillRect(check, selected ? st::overviewFileChecked : st::overviewFileCheck); - p.drawSpriteCenter(check, st::defaultCheckbox.checkIcon); + st::defaultCheckbox.checkIcon.paint(p, QPoint(rthumb.width() - st::defaultCheckbox.diameter, rthumb.y() + rthumb.height() - st::defaultCheckbox.diameter), _width); } } } @@ -979,13 +979,13 @@ Link::Link(HistoryMedia *media, HistoryItem *parent) : ItemBase(parent) { tw = convertScale(_page->document->thumb->width()); th = convertScale(_page->document->thumb->height()); } - if (tw > st::dlgPhotoSize) { + if (tw > st::linksPhotoSize) { if (th > tw) { - th = th * st::dlgPhotoSize / tw; - tw = st::dlgPhotoSize; - } else if (th > st::dlgPhotoSize) { - tw = tw * st::dlgPhotoSize / th; - th = st::dlgPhotoSize; + th = th * st::linksPhotoSize / tw; + tw = st::linksPhotoSize; + } else if (th > st::linksPhotoSize) { + tw = tw * st::linksPhotoSize / th; + th = st::linksPhotoSize; } } _pixw = qMax(tw, 1); @@ -1020,15 +1020,15 @@ void Link::initDimensions() { _minh += st::semiboldFont->height; } if (!_text.isEmpty()) { - _minh += qMin(3 * st::normalFont->height, _text.countHeight(_maxw - st::dlgPhotoSize - st::dlgPhotoPadding)); + _minh += qMin(3 * st::normalFont->height, _text.countHeight(_maxw - st::linksPhotoSize - st::linksPhotoPadding)); } _minh += _links.size() * st::normalFont->height; - _minh = qMax(_minh, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder; + _minh = qMax(_minh, int32(st::linksPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder; } int32 Link::resizeGetHeight(int32 width) { _width = qMin(width, _maxw); - int32 w = _width - st::dlgPhotoSize - st::dlgPhotoPadding; + int32 w = _width - st::linksPhotoSize - st::linksPhotoPadding; for (int32 i = 0, l = _links.size(); i < l; ++i) { _links.at(i).lnk->setFullDisplayed(w >= _links.at(i).width); } @@ -1038,54 +1038,54 @@ int32 Link::resizeGetHeight(int32 width) { _height += st::semiboldFont->height; } if (!_text.isEmpty()) { - _height += qMin(3 * st::normalFont->height, _text.countHeight(_width - st::dlgPhotoSize - st::dlgPhotoPadding)); + _height += qMin(3 * st::normalFont->height, _text.countHeight(_width - st::linksPhotoSize - st::linksPhotoPadding)); } _height += _links.size() * st::normalFont->height; - _height = qMax(_height, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder; + _height = qMax(_height, int32(st::linksPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder; return _height; } void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const { - int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; - if (clip.intersects(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width))) { + int32 left = st::linksPhotoSize + st::linksPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; + if (clip.intersects(rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width))) { if (_page && _page->photo) { QPixmap pix; if (_page->photo->medium->loaded()) { - pix = _page->photo->medium->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); + pix = _page->photo->medium->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize); } else if (_page->photo->loaded()) { - pix = _page->photo->full->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); + pix = _page->photo->full->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize); } else { - pix = _page->photo->thumb->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); + pix = _page->photo->thumb->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize); } p.drawPixmapLeft(0, top, _width, pix); } else if (_page && _page->document && !_page->document->thumb->isNull()) { - p.drawPixmapLeft(0, top, _width, _page->document->thumb->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize)); + p.drawPixmapLeft(0, top, _width, _page->document->thumb->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize)); } else { int32 index = _letter.isEmpty() ? 0 : (_letter.at(0).unicode() % 4); switch (index) { - case 0: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileRedColor, DocRedCorners); break; - case 1: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileYellowColor, DocYellowCorners); break; - case 2: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileGreenColor, DocGreenCorners); break; - case 3: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileBlueColor, DocBlueCorners); break; + case 0: App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::msgFileRedColor, DocRedCorners); break; + case 1: App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::msgFileYellowColor, DocYellowCorners); break; + case 2: App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::msgFileGreenColor, DocGreenCorners); break; + case 3: App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::msgFileBlueColor, DocBlueCorners); break; } if (!_letter.isEmpty()) { p.setFont(st::linksLetterFont->f); p.setPen(st::white->p); - p.drawText(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), _letter, style::al_center); + p.drawText(rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), _letter, style::al_center); } } if (selection == FullSelection) { - App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::overviewPhotoSelectOverlay, PhotoSelectOverlayCorners); - st::overviewLinksChecked.paint(p, QPoint(st::dlgPhotoSize - st::overviewLinksChecked.width(), top + st::dlgPhotoSize - st::overviewLinksChecked.height()), _width); + App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::overviewPhotoSelectOverlay, PhotoSelectOverlayCorners); + st::overviewLinksChecked.paint(p, QPoint(st::linksPhotoSize - st::overviewLinksChecked.width(), top + st::linksPhotoSize - st::overviewLinksChecked.height()), _width); } else if (context->selecting) { - st::overviewLinksCheck.paint(p, QPoint(st::dlgPhotoSize - st::overviewLinksCheck.width(), top + st::dlgPhotoSize - st::overviewLinksCheck.height()), _width); + st::overviewLinksCheck.paint(p, QPoint(st::linksPhotoSize - st::overviewLinksCheck.width(), top + st::linksPhotoSize - st::overviewLinksCheck.height()), _width); } } if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { - top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; + top += (st::linksPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; } else { top = st::linksTextTop; } @@ -1123,14 +1123,14 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P } void Link::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { - int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; - if (rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width).contains(x, y)) { + int32 left = st::linksPhotoSize + st::linksPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; + if (rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width).contains(x, y)) { link = _photol; return; } if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { - top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; + top += (st::linksPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; } if (!_title.isEmpty()) { if (rtlrect(left, top, qMin(w, _titlew), st::semiboldFont->height, _width).contains(x, y)) { diff --git a/Telegram/SourceFiles/profile/profile.style b/Telegram/SourceFiles/profile/profile.style index 3b8b93ab1..8c3de42fc 100644 --- a/Telegram/SourceFiles/profile/profile.style +++ b/Telegram/SourceFiles/profile/profile.style @@ -24,29 +24,30 @@ using "basic_types.style"; profileBg: windowBg; profileTopBarHeight: topBarHeight; -profileTopBarBackIconFg: #51b3e0; +profileTopBarBackIconFg: #0290d7; profileTopBarBackIcon: icon { { "topbar_back_arrow", profileTopBarBackIconFg }, }; -profileTopBarBackIconPosition: point(15px, 19px); +profileTopBarBackIconPosition: point(15px, 20px); profileTopBarBackFont: font(14px); profileTopBarBackFg: #1485c2; profileTopBarBackPosition: point(32px, 17px); -profileFixedBarButton: flatButton(topBarButton) { +profileFixedBarButton: BoxButton(topBarButton) { } profileMarginTop: 13px; profilePhotoSize: 112px; profilePhotoLeftMin: 18px; -profilePhotoLeftMax: 45px; +profilePhotoLeftMax: 35px; profilePhotoDuration: 500; profileNameLeft: 26px; profileNameTop: 9px; profileNameLabel: flatLabel(labelDefFlat) { margin: margins(10px, 5px, 10px, 5px); - font: font(16px); + font: font(16px semibold); width: 160px; maxHeight: 24px; + textFg: #333333; } profileNameTextStyle: textStyle(defaultTextStyle) { } @@ -57,18 +58,18 @@ profileStatusFg: windowSubTextFg; profileStatusFgActive: windowActiveTextFg; profileMarginBottom: 30px; -profileActiveBg: #3fb0e4; profileButtonLeft: 27px; profileButtonTop: 88px; profileButtonSkip: 10px; profilePrimaryButton: BoxButton { textFg: #ffffff; textFgOver: #ffffff; - textBg: profileActiveBg; - textBgOver: profileActiveBg; + textBg: windowActiveBg; + textBgOver: windowActiveBg; width: -34px; height: 34px; + padding: margins(0px, 0px, 0px, 0px); textTop: 8px; @@ -76,13 +77,13 @@ profilePrimaryButton: BoxButton { duration: 200; } profileSecondaryButton: BoxButton(profilePrimaryButton) { - textFg: #189dda; - textFgOver: #189dda; + textFg: #2b99d5; + textFgOver: #2b99d5; textBg: #ffffff; textBgOver: #f2f7fa; } profileAddMemberIcon: icon { - { "profile_add_member", profileActiveBg, point(20px, 10px) }, + { "profile_add_member", windowActiveBg, point(20px, 10px) }, }; profileAddMemberButton: BoxButton(profileSecondaryButton) { width: 62px; @@ -90,7 +91,7 @@ profileAddMemberButton: BoxButton(profileSecondaryButton) { } profileDropAreaBg: profileBg; -profileDropAreaFg: profileActiveBg; +profileDropAreaFg: windowActiveBg; profileDropAreaPadding: margins(25px, 3px, 25px, 20px); profileDropAreaTitleFont: font(24px); profileDropAreaTitleTop: 30px; @@ -120,7 +121,7 @@ profileBlockMarginRight: 10px; profileBlockMarginBottom: 4px; profileBlockTitleHeight: 25px; profileBlockTitleFont: font(14px semibold); -profileBlockTitleFg: black; +profileBlockTitleFg: #333333; profileBlockTitlePosition: point(24px, 0px); profileBlockLabel: flatLabel(labelDefFlat) { textFg: windowSubTextFg; @@ -153,7 +154,7 @@ profileMemberStatusFg: windowSubTextFg; profileMemberStatusFgOver: windowSubTextFg; profileMemberStatusFgActive: windowActiveTextFg; profileMemberAdminIcon: icon { - { "profile_admin_star", profileActiveBg, point(4px, 2px) }, + { "profile_admin_star", #3babe7, point(4px, 2px) }, }; profileLimitReachedLabel: flatLabel(labelDefFlat) { width: 180px; @@ -167,3 +168,9 @@ profileReportReasonOther: InputArea(defaultInputArea) { textMargins: margins(1px, 6px, 1px, 4px); heightMax: 115px; } + +profileVerifiedCheckPosition: point(-3px, 7px); +profileVerifiedCheck: icon { + { "profile_verified_star", #4abcf1 }, + { "profile_verified_check", #ffffff, point(4px, 4px) } +}; diff --git a/Telegram/SourceFiles/profile/profile_cover.cpp b/Telegram/SourceFiles/profile/profile_cover.cpp index 974d2db72..a3928162a 100644 --- a/Telegram/SourceFiles/profile/profile_cover.cpp +++ b/Telegram/SourceFiles/profile/profile_cover.cpp @@ -129,9 +129,12 @@ void CoverWidget::refreshNameGeometry(int newWidth) { int infoLeft = _userpicButton->x() + _userpicButton->width(); int nameLeft = infoLeft + st::profileNameLeft - st::profileNameLabel.margin.left(); int nameTop = _userpicButton->y() + st::profileNameTop - st::profileNameLabel.margin.top(); - int nameWidth = newWidth - infoLeft - st::profileNameLeft - st::profileButtonSkip; + int nameWidth = newWidth - infoLeft - st::profileNameLeft; + if (_peer->isVerified()) { + nameWidth -= st::profileVerifiedCheckPosition.x() + st::profileVerifiedCheck.width(); + } int marginsAdd = st::profileNameLabel.margin.left() + st::profileNameLabel.margin.right(); - _name.resizeToWidth(qMin(nameWidth, _name.naturalWidth()) + marginsAdd); + _name.resizeToWidth(qMin(nameWidth - marginsAdd, _name.naturalWidth()) + marginsAdd); _name.moveToLeft(nameLeft, nameTop); } @@ -183,6 +186,10 @@ void CoverWidget::paintEvent(QPaintEvent *e) { p.setPen(_statusTextIsOnline ? st::profileStatusFgActive : st::profileStatusFg); p.drawTextLeft(_statusPosition.x(), _statusPosition.y(), width(), _statusText); + if (_peer->isVerified()) { + st::profileVerifiedCheck.paint(p, QPoint(_name.x() + _name.width(), _name.y()) + st::profileVerifiedCheckPosition, width()); + } + paintDivider(p); } @@ -407,6 +414,7 @@ void CoverWidget::clearButtons() { void CoverWidget::addButton(const QString &text, const char *slot, const style::BoxButton *replacementStyle) { auto &buttonStyle = _buttons.isEmpty() ? st::profilePrimaryButton : st::profileSecondaryButton; auto button = new Ui::RoundButton(this, text, buttonStyle); + button->setTextTransform(Ui::RoundButton::TextTransform::ToUpper); connect(button, SIGNAL(clicked()), this, slot); button->show(); diff --git a/Telegram/SourceFiles/profile/profile_fixed_bar.cpp b/Telegram/SourceFiles/profile/profile_fixed_bar.cpp index 8a1582f67..f7b9d9a7d 100644 --- a/Telegram/SourceFiles/profile/profile_fixed_bar.cpp +++ b/Telegram/SourceFiles/profile/profile_fixed_bar.cpp @@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "profile/profile_fixed_bar.h" #include "styles/style_profile.h" +#include "ui/buttons/round_button.h" #include "lang.h" #include "mainwidget.h" #include "boxes/addcontactbox.h" @@ -165,7 +166,7 @@ void FixedBar::addRightAction(RightActionType type, const QString &text, const c } _rightActions[_currentAction].type = type; delete _rightActions[_currentAction].button; - _rightActions[_currentAction].button = new FlatButton(this, text, st::profileFixedBarButton); + _rightActions[_currentAction].button = new Ui::RoundButton(this, text, st::profileFixedBarButton); connect(_rightActions[_currentAction].button, SIGNAL(clicked()), this, slot); bool showButton = !_animatingMode && (type != RightActionType::ShareContact || !_hideShareContactButton); _rightActions[_currentAction].button->setVisible(showButton); diff --git a/Telegram/SourceFiles/profile/profile_fixed_bar.h b/Telegram/SourceFiles/profile/profile_fixed_bar.h index 0b6d131e0..de03c7e0d 100644 --- a/Telegram/SourceFiles/profile/profile_fixed_bar.h +++ b/Telegram/SourceFiles/profile/profile_fixed_bar.h @@ -26,6 +26,10 @@ namespace Notify { struct PeerUpdate; } // namespace Notify +namespace Ui { +class RoundButton; +} // namespace Ui + namespace Profile { class BackButton; @@ -96,7 +100,7 @@ private: int _currentAction = 0; struct RightAction { RightActionType type = RightActionType::None; - FlatButton *button = nullptr; + Ui::RoundButton *button = nullptr; }; QList _rightActions; diff --git a/Telegram/SourceFiles/profile/profile_members_widget.cpp b/Telegram/SourceFiles/profile/profile_members_widget.cpp index 78eddd68c..80d9d8f99 100644 --- a/Telegram/SourceFiles/profile/profile_members_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_members_widget.cpp @@ -426,6 +426,9 @@ void MembersWidget::fillChatMembers(ChatData *chat) { } void MembersWidget::setMemberFlags(Member *member, ChatData *chat) { + auto isCreator = (chat->creator == peerToUser(member->user->id)); + auto isAdmin = chat->admins.contains(member->user); + member->isAdmin = isCreator || isAdmin; if (member->user->id == peerFromUser(MTP::authedId())) { member->canBeKicked = false; } else if (chat->amCreator() || (chat->amAdmin() && !member->isAdmin)) { @@ -433,7 +436,6 @@ void MembersWidget::setMemberFlags(Member *member, ChatData *chat) { } else { member->canBeKicked = chat->invitedByMe.contains(member->user); } - member->isAdmin = chat->admins.contains(member->user); } MembersWidget::Member *MembersWidget::addUser(ChannelData *megagroup, UserData *user) { @@ -490,6 +492,9 @@ bool MembersWidget::addUsersToEnd(ChannelData *megagroup) { } void MembersWidget::setMemberFlags(Member *member, ChannelData *megagroup) { + auto amCreatorOrAdmin = (peerFromUser(member->user->id) == MTP::authedId()) && (megagroup->amCreator() || megagroup->amEditor()); + auto isAdmin = megagroup->mgInfo->lastAdmins.contains(member->user); + member->isAdmin = amCreatorOrAdmin || isAdmin; if (member->user->isSelf()) { member->canBeKicked = false; } else if (megagroup->amCreator() || (megagroup->amEditor() && !member->isAdmin)) { @@ -497,7 +502,6 @@ void MembersWidget::setMemberFlags(Member *member, ChannelData *megagroup) { } else { member->canBeKicked = false; } - member->isAdmin = megagroup->mgInfo->lastAdmins.contains(member->user); } MembersWidget::Member *MembersWidget::getMember(UserData *user) { @@ -640,7 +644,7 @@ void ChannelMembersWidget::addButton(const QString &text, ChildWidgetsetText(text); } else { - (*button) = new Ui::LeftOutlineButton(this, text); + (*button) = new Ui::LeftOutlineButton(this, text, st::defaultLeftOutlineButton); (*button)->show(); connect(*button, SIGNAL(clicked()), this, slot); } diff --git a/Telegram/SourceFiles/profile/profile_settings_widget.cpp b/Telegram/SourceFiles/profile/profile_settings_widget.cpp index 706b3958a..3fe1c033e 100644 --- a/Telegram/SourceFiles/profile/profile_settings_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_settings_widget.cpp @@ -127,7 +127,7 @@ void SettingsWidget::refreshManageAdminsButton() { }; _manageAdmins.destroy(); if (hasManageAdmins()) { - _manageAdmins = new Ui::LeftOutlineButton(this, lang(lng_profile_manage_admins)); + _manageAdmins = new Ui::LeftOutlineButton(this, lang(lng_profile_manage_admins), st::defaultLeftOutlineButton); _manageAdmins->show(); connect(_manageAdmins, SIGNAL(clicked()), this, SLOT(onManageAdmins())); } @@ -148,7 +148,7 @@ void SettingsWidget::refreshInviteLinkButton() { }; auto inviteLinkText = getInviteLinkText(); if (!inviteLinkText.isEmpty()) { - _inviteLink = new Ui::LeftOutlineButton(this, inviteLinkText); + _inviteLink = new Ui::LeftOutlineButton(this, inviteLinkText, st::defaultLeftOutlineButton); _inviteLink->show(); connect(_inviteLink, SIGNAL(clicked()), this, SLOT(onInviteLink())); } diff --git a/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp b/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp index f7263f22b..313aaad78 100644 --- a/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp @@ -108,7 +108,7 @@ void SharedMediaWidget::refreshButton(MediaOverviewType type) { if (_mediaButtons[type]) { _mediaButtons[type]->setText(text); } else { - _mediaButtons[type] = new Ui::LeftOutlineButton(this, text); + _mediaButtons[type] = new Ui::LeftOutlineButton(this, text, st::defaultLeftOutlineButton); _mediaButtons[type]->show(); connect(_mediaButtons[type], SIGNAL(clicked()), this, SLOT(onMediaChosen())); } diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp index 72b5f21aa..a58b4715b 100644 --- a/Telegram/SourceFiles/pspecific_mac.cpp +++ b/Telegram/SourceFiles/pspecific_mac.cpp @@ -509,7 +509,9 @@ void PsMainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) { QPixmap pix = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->history()->peer->genUserpic(st::notifyMacPhotoSize) : QPixmap(); QString msg = (!App::passcoded() && cNotifyView() <= dbinvShowPreview) ? (fwdCount < 2 ? item->notificationText() : lng_forward_messages(lt_count, fwdCount)) : lang(lng_notification_preview); - _private.showNotify(item->history()->peer->id, item->id, pix, title, subtitle, msg, !App::passcoded() && (cNotifyView() <= dbinvShowPreview)); + bool withReply = !App::passcoded() && (cNotifyView() <= dbinvShowPreview) && item->history()->peer->canWrite(); + + _private.showNotify(item->history()->peer->id, item->id, pix, title, subtitle, msg, withReply); } bool PsMainWindow::eventFilter(QObject *obj, QEvent *evt) { diff --git a/Telegram/SourceFiles/ui/buttons/round_button.cpp b/Telegram/SourceFiles/ui/buttons/round_button.cpp index f0ab81ce4..758d7efb7 100644 --- a/Telegram/SourceFiles/ui/buttons/round_button.cpp +++ b/Telegram/SourceFiles/ui/buttons/round_button.cpp @@ -24,8 +24,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Ui { RoundButton::RoundButton(QWidget *parent, const QString &text, const style::BoxButton &st) : Button(parent) -, _text(text.toUpper()) -, _fullText(text.toUpper()) +, _text(text) +, _fullText(text) , _textWidth(st.font->width(_text)) , _st(st) , a_textBgOverOpacity(0) @@ -36,34 +36,62 @@ RoundButton::RoundButton(QWidget *parent, const QString &text, const style::BoxB setCursor(style::cur_pointer); } +void RoundButton::setTextTransform(TextTransform transform) { + _transform = transform; + updateText(); +} + void RoundButton::setText(const QString &text) { - _text = text; _fullText = text; + updateText(); +} + +void RoundButton::setFullWidth(int newFullWidth) { + _fullWidthOverride = newFullWidth; + resizeToText(); +} + +void RoundButton::updateText() { + if (_transform == TextTransform::ToUpper) { + _text = _fullText.toUpper(); + } else { + _text = _fullText; + } _textWidth = _st.font->width(_text); resizeToText(); } +int RoundButton::textWidth() const { + return _textWidth; +} + void RoundButton::resizeToText() { - if (_st.width <= 0) { - resize(_textWidth - _st.width, _st.height); + if (_fullWidthOverride < 0) { + resize(_textWidth - _fullWidthOverride, _st.height + _st.padding.top() + _st.padding.bottom()); + } else if (_st.width <= 0) { + resize(_textWidth - _st.width + _st.padding.left() + _st.padding.right(), _st.height + _st.padding.top() + _st.padding.bottom()); } else { if (_st.width < _textWidth + (_st.height - _st.font->height)) { _text = _st.font->elided(_fullText, qMax(_st.width - (_st.height - _st.font->height), 1)); _textWidth = _st.font->width(_text); } - resize(_st.width, _st.height); + resize(_st.width + _st.padding.left() + _st.padding.right(), _st.height + _st.padding.top() + _st.padding.bottom()); } } void RoundButton::paintEvent(QPaintEvent *e) { Painter p(this); - App::roundRect(p, rect(), _st.textBg); + auto rounded = rtlrect(rect().marginsRemoved(_st.padding), width()); + if (_fullWidthOverride < 0) { + rounded = QRect(-_fullWidthOverride / 4, rounded.top(), _textWidth - _fullWidthOverride / 2, rounded.height()); + } + App::roundRect(p, rounded, _st.textBg); float64 o = a_textBgOverOpacity.current(); if (o > 0) { p.setOpacity(o); - App::roundRect(p, rect(), _st.textBgOver); + App::roundRect(p, rounded, _st.textBgOver); p.setOpacity(1); } if (!_text.isEmpty()) { @@ -73,9 +101,13 @@ void RoundButton::paintEvent(QPaintEvent *e) { p.setPen(_st.textFg); } p.setFont(_st.font); - p.drawText((width() - _textWidth) / 2, _st.textTop + _st.font->ascent, _text); + int textLeft = _st.padding.left() + ((width() - _textWidth - _st.padding.left() - _st.padding.right()) / 2); + if (_fullWidthOverride < 0) { + textLeft = -_fullWidthOverride / 2; + } + p.drawTextLeft(textLeft, _st.padding.top() + _st.textTop, width(), _text); } - _st.icon.paint(p, QPoint(0, 0), width()); + _st.icon.paint(p, QPoint(_st.padding.left(), _st.padding.right()), width()); } void RoundButton::step_over(float64 ms, bool timer) { diff --git a/Telegram/SourceFiles/ui/buttons/round_button.h b/Telegram/SourceFiles/ui/buttons/round_button.h index aa3e1cfaa..b7c9d51a4 100644 --- a/Telegram/SourceFiles/ui/buttons/round_button.h +++ b/Telegram/SourceFiles/ui/buttons/round_button.h @@ -29,6 +29,15 @@ public: RoundButton(QWidget *parent, const QString &text, const style::BoxButton &st); void setText(const QString &text); + int textWidth() const; + + void setFullWidth(int newFullWidth); + + enum class TextTransform { + NoTransform, + ToUpper, + }; + void setTextTransform(TextTransform transform); protected: void paintEvent(QPaintEvent *e) override; @@ -38,10 +47,12 @@ protected: private: void step_over(float64 ms, bool timer); + void updateText(); void resizeToText(); QString _text, _fullText; int _textWidth; + int _fullWidthOverride = 0; const style::BoxButton &_st; @@ -49,6 +60,8 @@ private: anim::cvalue a_textFg; Animation _a_over; + TextTransform _transform = TextTransform::NoTransform; + }; } // namespace Ui diff --git a/Telegram/SourceFiles/ui/flatbutton.cpp b/Telegram/SourceFiles/ui/flatbutton.cpp index 691f6e9b5..8255e7159 100644 --- a/Telegram/SourceFiles/ui/flatbutton.cpp +++ b/Telegram/SourceFiles/ui/flatbutton.cpp @@ -24,7 +24,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org FlatButton::FlatButton(QWidget *parent, const QString &text, const style::flatButton &st) : Button(parent) , _text(text) , _st(st) -, _autoFontPadding(0) , a_bg(st.bgColor->c) , a_text(st.color->c) , _a_appearance(animation(this, &FlatButton::step_appearance)) @@ -63,35 +62,10 @@ void FlatButton::setWidth(int32 w) { resize(_st.width, height()); } -void FlatButton::setAutoFontSize(int32 padding, const QString &txt) { - _autoFontPadding = padding; - if (_autoFontPadding) { - _textForAutoSize = txt; - resizeEvent(0); - } else { - _textForAutoSize = QString(); - _autoFont = style::font(); - } - update(); -} - int32 FlatButton::textWidth() const { return _st.font->width(_text); } -void FlatButton::resizeEvent(QResizeEvent *e) { - if (_autoFontPadding) { - _autoFont = _st.font; - for (int32 s = _st.font->f.pixelSize(); s >= st::fsize; --s) { - _autoFont = style::font(s, _st.font->flags(), _st.font->family()); - if (2 * _autoFontPadding + _autoFont->width(_textForAutoSize) <= width()) { - break; - } - } - } - return Button::resizeEvent(e); -} - void FlatButton::step_appearance(float64 ms, bool timer) { float64 dt = ms / _st.duration; if (dt >= 1) { @@ -129,12 +103,11 @@ void FlatButton::paintEvent(QPaintEvent *e) { p.setOpacity(_opacity); p.fillRect(r, a_bg.current()); - p.setFont((_autoFont ? _autoFont : ((_state & StateOver) ? _st.overFont : _st.font))->f); + p.setFont((_state & StateOver) ? _st.overFont : _st.font); p.setRenderHint(QPainter::TextAntialiasing); p.setPen(a_text.current()); int32 top = (_state & StateOver) ? ((_state & StateDown) ? _st.downTextTop : _st.overTextTop) : _st.textTop; - if (_autoFont) top += (_st.font->height - _autoFont->height) / 2; r.setTop(top); p.drawText(r, _text, style::al_top); diff --git a/Telegram/SourceFiles/ui/flatbutton.h b/Telegram/SourceFiles/ui/flatbutton.h index b02bae140..3adbe5a1d 100644 --- a/Telegram/SourceFiles/ui/flatbutton.h +++ b/Telegram/SourceFiles/ui/flatbutton.h @@ -31,8 +31,6 @@ public: FlatButton(QWidget *parent, const QString &text, const style::flatButton &st); - void resizeEvent(QResizeEvent *e); - void step_appearance(float64 ms, bool timer); void paintEvent(QPaintEvent *e); void setOpacity(float64 o); @@ -40,7 +38,6 @@ public: void setText(const QString &text); void setWidth(int32 w); - void setAutoFontSize(int32 padding, const QString &txt); int32 textWidth() const; @@ -58,9 +55,6 @@ private: style::flatButton _st; - int32 _autoFontPadding; - style::font _autoFont; - anim::cvalue a_bg, a_text; Animation _a_appearance; diff --git a/Telegram/SourceFiles/ui/flatcheckbox.cpp b/Telegram/SourceFiles/ui/flatcheckbox.cpp index d45587077..d1d64ab1f 100644 --- a/Telegram/SourceFiles/ui/flatcheckbox.cpp +++ b/Telegram/SourceFiles/ui/flatcheckbox.cpp @@ -351,7 +351,7 @@ void Checkbox::paintEvent(QPaintEvent *e) { p.setRenderHint(QPainter::HighQualityAntialiasing, false); if (checked > 0) { - p.drawSpriteCenter(_checkRect, _st.checkIcon); + _st.checkIcon.paint(p, QPoint(0, 0), width()); } } if (_checkRect.contains(r)) return; diff --git a/Telegram/SourceFiles/window/top_bar_widget.cpp b/Telegram/SourceFiles/window/top_bar_widget.cpp index 2fbb27e5b..6c1772c79 100644 --- a/Telegram/SourceFiles/window/top_bar_widget.cpp +++ b/Telegram/SourceFiles/window/top_bar_widget.cpp @@ -27,6 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "shortcuts.h" #include "lang.h" #include "ui/buttons/peer_avatar_button.h" +#include "ui/buttons/round_button.h" #include "ui/flatbutton.h" namespace Window { @@ -37,19 +38,15 @@ TopBarWidget::TopBarWidget(MainWidget *w) : TWidget(w) , _selPeer(0) , _selCount(0) , _canDelete(false) -, _selStrLeft(-st::topBarButton.width / 2) +, _selStrLeft((-st::topBarClearButton.width + st::topBarClearButton.padding.left() + st::topBarClearButton.padding.right()) / 2) , _selStrWidth(0) , _animating(false) -, _clearSelection(this, lang(lng_selected_clear), st::topBarButton) +, _clearSelection(this, lang(lng_selected_clear), st::topBarClearButton) , _forward(this, lang(lng_selected_forward), st::topBarActionButton) , _delete(this, lang(lng_selected_delete), st::topBarActionButton) , _selectionButtonsWidth(_clearSelection->width() + _forward->width() + _delete->width()) , _forwardDeleteWidth(qMax(_forward->textWidth(), _delete->textWidth())) , _info(this, nullptr, st::infoButton) -, _edit(this, lang(lng_profile_edit_contact), st::topBarButton) -, _leaveGroup(this, lang(lng_profile_delete_and_exit), st::topBarButton) -, _addContact(this, lang(lng_profile_add_contact), st::topBarButton) -, _deleteContact(this, lang(lng_profile_delete_contact), st::topBarButton) , _mediaType(this, lang(lng_media_type), st::topBarButton) , _search(this, st::topBarSearch) { @@ -57,10 +54,6 @@ TopBarWidget::TopBarWidget(MainWidget *w) : TWidget(w) connect(_delete, SIGNAL(clicked()), this, SLOT(onDeleteSelection())); connect(_clearSelection, SIGNAL(clicked()), this, SLOT(onClearSelection())); connect(_info, SIGNAL(clicked()), this, SLOT(onInfoClicked())); - connect(_addContact, SIGNAL(clicked()), this, SLOT(onAddContact())); - connect(_deleteContact, SIGNAL(clicked()), this, SLOT(onDeleteContact())); - connect(_edit, SIGNAL(clicked()), this, SLOT(onEdit())); - connect(_leaveGroup, SIGNAL(clicked()), this, SLOT(onDeleteAndExit())); connect(_search, SIGNAL(clicked()), this, SLOT(onSearch())); setCursor(style::cur_pointer); @@ -84,65 +77,6 @@ void TopBarWidget::onInfoClicked() { if (p) Ui::showPeerProfile(p); } -void TopBarWidget::onAddContact() { - PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0; - UserData *u = p ? p->asUser() : 0; - if (u) Ui::showLayer(new AddContactBox(u->firstName, u->lastName, u->phone().isEmpty() ? App::phoneFromSharedContact(peerToUser(u->id)) : u->phone())); -} - -void TopBarWidget::onEdit() { - PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0; - if (p) { - if (p->isChannel()) { - Ui::showLayer(new EditChannelBox(p->asChannel())); - } else if (p->isChat()) { - Ui::showLayer(new EditNameTitleBox(p)); - } else if (p->isUser()) { - Ui::showLayer(new AddContactBox(p->asUser())); - } - } -} - -void TopBarWidget::onDeleteContact() { - PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0; - UserData *u = p ? p->asUser() : 0; - if (u) { - ConfirmBox *box = new ConfirmBox(lng_sure_delete_contact(lt_contact, p->name), lang(lng_box_delete)); - connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteContactSure())); - Ui::showLayer(box); - } -} - -void TopBarWidget::onDeleteContactSure() { - PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0; - UserData *u = p ? p->asUser() : 0; - if (u) { - Ui::showChatsList(); - Ui::hideLayer(); - MTP::send(MTPcontacts_DeleteContact(u->inputUser), App::main()->rpcDone(&MainWidget::deletedContact, u)); - } -} - -void TopBarWidget::onDeleteAndExit() { - PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0; - ChatData *c = p ? p->asChat() : 0; - if (c) { - ConfirmBox *box = new ConfirmBox(lng_sure_delete_and_exit(lt_group, p->name), lang(lng_box_leave), st::attentionBoxButton); - connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteAndExitSure())); - Ui::showLayer(box); - } -} - -void TopBarWidget::onDeleteAndExitSure() { - PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0; - ChatData *c = p ? p->asChat() : 0; - if (c) { - Ui::showChatsList(); - Ui::hideLayer(); - MTP::send(MTPmessages_DeleteChatUser(c->inputChat, App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistoryAfterLeave, p), App::main()->rpcFail(&MainWidget::leaveChatFailed, p)); - } -} - void TopBarWidget::onSearch() { Shortcuts::launch(qsl("search")); } @@ -197,7 +131,7 @@ void TopBarWidget::paintEvent(QPaintEvent *e) { } else { p.setFont(st::linkFont); p.setPen(st::btnDefLink.color); - p.drawText(_selStrLeft, st::topBarButton.textTop + st::linkFont->ascent, _selStr); + p.drawText(_selStrLeft, st::topBarClearButton.padding.top() + st::topBarClearButton.textTop + st::linkFont->ascent, _selStr); } } @@ -211,8 +145,10 @@ void TopBarWidget::mousePressEvent(QMouseEvent *e) { void TopBarWidget::resizeEvent(QResizeEvent *e) { int32 r = width(); if (!_forward->isHidden() || !_delete->isHidden()) { - int32 fullW = r - (_selectionButtonsWidth + (_selStrWidth - st::topBarButton.width) + st::topBarActionSkip); - int32 selectedClearWidth = st::topBarButton.width, forwardDeleteWidth = st::topBarActionButton.width - _forwardDeleteWidth, skip = st::topBarActionSkip; + int fullW = r - (_selectionButtonsWidth + (_selStrWidth - st::topBarClearButton.width + st::topBarClearButton.padding.left() + st::topBarClearButton.padding.right()) + st::topBarActionSkip); + int selectedClearWidth = st::topBarClearButton.width - st::topBarClearButton.padding.left() - st::topBarClearButton.padding.right(); + int forwardDeleteWidth = st::topBarActionButton.width - _forwardDeleteWidth; + int skip = st::topBarActionSkip; while (fullW < 0) { int fit = 0; if (selectedClearWidth < -2 * (st::topBarMinPadding + 1)) { @@ -245,7 +181,7 @@ void TopBarWidget::resizeEvent(QResizeEvent *e) { } if (fullW >= 0 || fit >= 3) break; } - _clearSelection->setWidth(selectedClearWidth); + _clearSelection->setFullWidth(selectedClearWidth); _forward->setWidth(_forwardDeleteWidth + forwardDeleteWidth); _delete->setWidth(_forwardDeleteWidth + forwardDeleteWidth); _selStrLeft = -selectedClearWidth / 2; @@ -262,20 +198,12 @@ void TopBarWidget::resizeEvent(QResizeEvent *e) { _clearSelection->move(r -= _clearSelection->width(), 0); } if (!_info->isHidden()) _info->move(r -= _info->width(), 0); - if (!_deleteContact->isHidden()) _deleteContact->move(r -= _deleteContact->width(), 0); - if (!_leaveGroup->isHidden()) _leaveGroup->move(r -= _leaveGroup->width(), 0); - if (!_edit->isHidden()) _edit->move(r -= _edit->width(), 0); - if (!_addContact->isHidden()) _addContact->move(r -= _addContact->width(), 0); if (!_mediaType->isHidden()) _mediaType->move(r -= _mediaType->width(), 0); _search->move(width() - (_info->isHidden() ? st::topBarForwardPadding.right() : _info->width()) - _search->width(), 0); } void TopBarWidget::startAnim() { _info->hide(); - _edit->hide(); - _leaveGroup->hide(); - _addContact->hide(); - _deleteContact->hide(); _clearSelection->hide(); _delete->hide(); _forward->hide(); @@ -295,74 +223,37 @@ void TopBarWidget::showAll() { resizeEvent(0); return; } - PeerData *p = nullptr/*App::main() ? App::main()->profilePeer() : 0*/, *h = App::main() ? App::main()->historyPeer() : 0, *o = App::main() ? App::main()->overviewPeer() : 0; - if (p && (p->isChat() || (p->isUser() && (p->asUser()->contact >= 0 || !App::phoneFromSharedContact(peerToUser(p->id)).isEmpty())))) { - if (p->isChat()) { - if (p->asChat()->canEdit()) { - _edit->show(); - } else { - _edit->hide(); - } - _leaveGroup->show(); - _addContact->hide(); - _deleteContact->hide(); - } else if (p->asUser()->contact > 0) { - _edit->show(); - _leaveGroup->hide(); - _addContact->hide(); - _deleteContact->show(); + PeerData *h = App::main() ? App::main()->historyPeer() : 0, *o = App::main() ? App::main()->overviewPeer() : 0; + if (_selCount) { + _clearSelection->show(); + if (_canDelete) { + _delete->show(); } else { - _edit->hide(); - _leaveGroup->hide(); - _addContact->show(); - _deleteContact->hide(); + _delete->hide(); } + _forward->show(); + _mediaType->hide(); + } else { _clearSelection->hide(); - _info->hide(); _delete->hide(); _forward->hide(); - _mediaType->hide(); - _search->hide(); - } else { - if (p && p->isChannel() && (p->asChannel()->amCreator() || (p->isMegagroup() && p->asChannel()->amEditor()))) { - _edit->show(); + if (App::main() && App::main()->mediaTypeSwitch()) { + _mediaType->show(); } else { - _edit->hide(); - } - _leaveGroup->hide(); - _addContact->hide(); - _deleteContact->hide(); - if (!p && _selCount) { - _clearSelection->show(); - if (_canDelete) { - _delete->show(); - } else { - _delete->hide(); - } - _forward->show(); _mediaType->hide(); - } else { - _clearSelection->hide(); - _delete->hide(); - _forward->hide(); - if (App::main() && App::main()->mediaTypeSwitch()) { - _mediaType->show(); - } else { - _mediaType->hide(); - } } - if (h && !o && !p && _clearSelection->isHidden()) { - if (Adaptive::OneColumn()) { - _info->setPeer(h); - _info->show(); - } else { - _info->hide(); - } - _search->show(); + } + if (h && !o && _clearSelection->isHidden()) { + if (Adaptive::OneColumn()) { + _info->setPeer(h); + _info->show(); } else { - _search->hide(); _info->hide(); } + _search->show(); + } else { + _search->hide(); + _info->hide(); } resizeEvent(nullptr); } @@ -382,7 +273,7 @@ void TopBarWidget::updateAdaptiveLayout() { showAll(); } -FlatButton *TopBarWidget::mediaTypeButton() { +Ui::RoundButton *TopBarWidget::mediaTypeButton() { return _mediaType; } diff --git a/Telegram/SourceFiles/window/top_bar_widget.h b/Telegram/SourceFiles/window/top_bar_widget.h index ae428cf0d..0f0d140bf 100644 --- a/Telegram/SourceFiles/window/top_bar_widget.h +++ b/Telegram/SourceFiles/window/top_bar_widget.h @@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Ui { class PeerAvatarButton; +class RoundButton; } // namespace Ui class FlatButton; class IconedButton; @@ -34,7 +35,6 @@ class TopBarWidget : public TWidget { Q_OBJECT public: - TopBarWidget(MainWidget *w); void enterEvent(QEvent *e) override; @@ -54,28 +54,19 @@ public: void updateAdaptiveLayout(); - FlatButton *mediaTypeButton(); + Ui::RoundButton *mediaTypeButton(); public slots: - void onForwardSelection(); void onDeleteSelection(); void onClearSelection(); void onInfoClicked(); - void onAddContact(); - void onEdit(); - void onDeleteContact(); - void onDeleteContactSure(); - void onDeleteAndExit(); - void onDeleteAndExitSure(); void onSearch(); signals: - void clicked(); private: - MainWidget *main(); anim::fvalue a_over; Animation _a_appearance; @@ -88,13 +79,12 @@ private: bool _animating; - ChildWidget _clearSelection; + ChildWidget _clearSelection; ChildWidget _forward, _delete; int _selectionButtonsWidth, _forwardDeleteWidth; ChildWidget _info; - ChildWidget _edit, _leaveGroup, _addContact, _deleteContact; - ChildWidget _mediaType; + ChildWidget _mediaType; ChildWidget _search; diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index 2f688472f..fbf0865c5 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -1231,6 +1231,7 @@ + diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index bb084e686..933b3e4b0 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -1296,6 +1296,9 @@ GeneratedFiles\Release + + SourceFiles\dialogs +