From 855d44b9d881e22ed5abf6b7dc4ad0d9ce649512 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 4 Jun 2016 00:46:45 +0300 Subject: [PATCH] Convert to megagroup information label added to new profiles. Tested members and admins realtime in new profiles for groups. --- Telegram/Resources/langs/lang.strings | 2 + Telegram/SourceFiles/app.cpp | 28 +++++++--- Telegram/SourceFiles/mainwidget.cpp | 1 - Telegram/SourceFiles/profile/profile.style | 7 +++ .../SourceFiles/profile/profile_cover.cpp | 6 ++- .../profile/profile_info_widget.cpp | 2 +- .../profile/profile_members_widget.cpp | 54 ++++++++++++++++--- .../profile/profile_members_widget.h | 3 ++ Telegram/SourceFiles/structs.cpp | 13 +++++ Telegram/SourceFiles/structs.h | 8 +-- Telegram/SourceFiles/ui/flatlabel.cpp | 2 + 11 files changed, 101 insertions(+), 25 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 753f79ac7..11459bc37 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -561,6 +561,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_action_pinned_media_sticker" = "a sticker"; "lng_profile_migrate_reached" = "{count:_not_used_|# member|# members} limit reached"; +"lng_profile_migrate_body" = "To get over this limit, you can upgrade your group to a supergroup."; +"lng_profile_migrate_learn_more" = "Learn more »"; "lng_profile_migrate_about" = "If you'd like to go over this limit, you can upgrade your group to a supergroup. In supergroups:"; "lng_profile_migrate_feature1" = "— The members limit is {count:_not_used_|# user|# users}"; "lng_profile_migrate_feature2" = "— New members see the entire chat history"; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index ef0e4859e..8220f20fb 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -570,6 +570,11 @@ namespace { auto cdata = data->asChat(); auto canEdit = cdata->canEdit(); + if (cdata->version < d.vversion.v) { + cdata->version = d.vversion.v; + cdata->invalidateParticipants(); + } + data->input = MTP_inputPeerChat(d.vid); cdata->setName(qs(d.vtitle)); cdata->setPhoto(d.vphoto); @@ -617,10 +622,6 @@ namespace { cdata->count = d.vparticipants_count.v; cdata->isForbidden = false; - if (cdata->version < d.vversion.v) { - cdata->version = d.vversion.v; - cdata->invalidateParticipants(); - } if (canEdit != cdata->canEdit()) { update.flags |= UpdateFlag::ChatCanEdit; } @@ -765,6 +766,7 @@ namespace { case mtpc_chatParticipants: { const auto &d(p.c_chatParticipants()); chat = App::chat(d.vchat_id.v); + auto canEdit = chat->canEdit(); if (!requestBotInfos || chat->version <= d.vversion.v) { // !requestBotInfos is true on getFullChat result chat->version = d.vversion.v; const auto &v(d.vparticipants.c_vector().v); @@ -836,9 +838,12 @@ namespace { } } } + if (canEdit != chat->canEdit()) { + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::ChatCanEdit); + } } break; } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged); + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged | Notify::PeerUpdate::Flag::AdminsChanged); if (chat && App::main()) { if (emitPeerUpdated) { App::main()->peerUpdated(chat); @@ -902,7 +907,6 @@ namespace { chat->version = d.vversion.v; chat->invalidateParticipants(); App::api()->requestPeer(chat); - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged); if (App::main()) { if (emitPeerUpdated) { App::main()->peerUpdated(chat); @@ -912,6 +916,7 @@ namespace { } } else if (chat->version <= d.vversion.v && chat->count > 0) { chat->version = d.vversion.v; + auto canEdit = chat->canEdit(); UserData *user = App::userLoaded(d.vuser_id.v); if (user) { if (chat->participants.isEmpty()) { @@ -953,6 +958,9 @@ namespace { chat->invalidateParticipants(); chat->count--; } + if (canEdit != chat->canEdit()) { + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::ChatCanEdit); + } Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged); if (App::main()) { if (emitPeerUpdated) { @@ -974,13 +982,14 @@ namespace { } chat->version = d.vversion.v; if (mtpIsTrue(d.venabled)) { - chat->flags |= MTPDchat::Flag::f_admins_enabled; if (!badVersion) { chat->invalidateParticipants(); } + chat->flags |= MTPDchat::Flag::f_admins_enabled; } else { chat->flags &= ~MTPDchat::Flag::f_admins_enabled; } + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged); if (emitPeerUpdated) { App::main()->peerUpdated(chat); } else { @@ -1004,6 +1013,7 @@ namespace { } } else if (chat->version <= d.vversion.v && chat->count > 0) { chat->version = d.vversion.v; + auto canEdit = chat->canEdit(); UserData *user = App::userLoaded(d.vuser_id.v); if (user) { if (mtpIsTrue(d.vis_admin)) { @@ -1024,6 +1034,10 @@ namespace { } else { chat->invalidateParticipants(); } + if (canEdit != chat->canEdit()) { + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::ChatCanEdit); + } + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged); if (App::main()) { if (emitPeerUpdated) { App::main()->peerUpdated(chat); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index eed803087..ff5f1bf4d 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -879,7 +879,6 @@ bool MainWidget::addParticipantsFail(ChannelData *channel, const RPCError &error void MainWidget::kickParticipant(ChatData *chat, UserData *user) { MTP::send(MTPmessages_DeleteChatUser(chat->inputChat, user->inputUser), rpcDone(&MainWidget::sentUpdatesReceived), rpcFail(&MainWidget::kickParticipantFail, chat)); - Ui::hideLayer(); Ui::showPeerHistory(chat->id, ShowAtTheEndMsgId); } diff --git a/Telegram/SourceFiles/profile/profile.style b/Telegram/SourceFiles/profile/profile.style index 2a365c8ea..7930ae441 100644 --- a/Telegram/SourceFiles/profile/profile.style +++ b/Telegram/SourceFiles/profile/profile.style @@ -154,3 +154,10 @@ profileMemberStatusFgActive: windowActiveTextFg; profileMemberAdminIcon: icon { { "profile_admin_star", profileActiveBg, point(4px, 2px) }, }; +profileLimitReachedLabel: flatLabel(labelDefFlat) { + width: 180px; + margin: margins(profileMemberPaddingLeft, 9px, profileMemberPaddingLeft, 6px); +} +profileLimitReachedStyle: textStyle(defaultTextStyle) { + lineHeight: 19px; +} diff --git a/Telegram/SourceFiles/profile/profile_cover.cpp b/Telegram/SourceFiles/profile/profile_cover.cpp index 7b039d9c8..73051c0e2 100644 --- a/Telegram/SourceFiles/profile/profile_cover.cpp +++ b/Telegram/SourceFiles/profile/profile_cover.cpp @@ -466,7 +466,11 @@ void CoverWidget::showSetPhotoBox(const QImage &img) { void CoverWidget::onAddMember() { if (_peerChat) { - Ui::showLayer(new ContactsBox(_peerChat, MembersFilterRecent)); + if (_peerChat->count >= Global::ChatSizeMax() && _peerChat->amCreator()) { + Ui::showLayer(new ConvertToSupergroupBox(_peerChat)); + } else { + Ui::showLayer(new ContactsBox(_peerChat, MembersFilterRecent)); + } } else if (_peerChannel && _peerChannel->mgInfo) { MembersAlreadyIn already; for_const (auto user, _peerChannel->mgInfo->lastParticipants) { diff --git a/Telegram/SourceFiles/profile/profile_info_widget.cpp b/Telegram/SourceFiles/profile/profile_info_widget.cpp index 221629635..12d7e8ec9 100644 --- a/Telegram/SourceFiles/profile/profile_info_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_info_widget.cpp @@ -142,7 +142,7 @@ void InfoWidget::refreshAbout() { _about.destroy(); auto aboutText = getAboutText(); if (!aboutText.isEmpty()) { - _about = new FlatLabel(this, QString(), FlatLabel::InitType::Simple, st::profileBlockTextPart); + _about = new FlatLabel(this, st::profileBlockTextPart); _about->show(); EntitiesInText aboutEntities; diff --git a/Telegram/SourceFiles/profile/profile_members_widget.cpp b/Telegram/SourceFiles/profile/profile_members_widget.cpp index 0c84ea26c..d4ab13ebb 100644 --- a/Telegram/SourceFiles/profile/profile_members_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_members_widget.cpp @@ -27,7 +27,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "ui/flatlabel.h" #include "boxes/contactsbox.h" #include "boxes/confirmbox.h" +#include "core/click_handler_types.h" #include "apiwrap.h" +#include "mainwidget.h" #include "observer_peer.h" #include "lang.h" @@ -119,7 +121,10 @@ int MembersWidget::resizeGetHeight(int newWidth) { if (_limitReachedInfo) { int limitReachedInfoWidth = newWidth - getListLeft(); + accumulate_min(limitReachedInfoWidth, st::profileBlockWideWidthMax); + _limitReachedInfo->resizeToWidth(limitReachedInfoWidth); + _limitReachedInfo->moveToLeft(getListLeft(), contentTop()); newHeight = getListTop(); } @@ -131,10 +136,12 @@ int MembersWidget::resizeGetHeight(int newWidth) { void MembersWidget::paintContents(Painter &p) { int left = getListLeft(); int top = getListTop(); + int memberRowWidth = width() - left; + accumulate_min(memberRowWidth, st::profileBlockWideWidthMax); if (_limitReachedInfo) { int infoTop = contentTop(); int infoHeight = top - infoTop - st::profileLimitReachedSkip; - paintOutlinedRect(p, left, infoTop, width() - left, infoHeight); + paintOutlinedRect(p, left, infoTop, memberRowWidth, infoHeight); } _now = unixtime(); @@ -215,7 +222,9 @@ void MembersWidget::updateSelection() { if (rtl()) mouse.setX(width() - mouse.x()); int left = getListLeft(); int top = getListTop(); - if (mouse.x() >= left && mouse.x() < width() && mouse.y() >= top) { + int memberRowWidth = width() - left; + accumulate_min(memberRowWidth, st::profileBlockWideWidthMax); + if (mouse.x() >= left && mouse.x() < left + memberRowWidth && mouse.y() >= top) { selected = (mouse.y() - top) / st::profileMemberHeight; if (selected >= _list.size()) { selected = -1; @@ -223,7 +232,7 @@ void MembersWidget::updateSelection() { int skip = st::profileMemberPhotoPosition.x(); int nameLeft = left + st::profileMemberNamePosition.x(); int nameTop = top + _selected * st::profileMemberHeight + st::profileMemberNamePosition.y(); - int nameWidth = width() - nameLeft - skip; + int nameWidth = memberRowWidth - st::profileMemberNamePosition.x() - skip; if (mouse.x() >= nameLeft + nameWidth - _removeWidth && mouse.x() < nameLeft + nameWidth) { if (mouse.y() >= nameTop && mouse.y() < nameTop + st::normalFont->height) { selectedKick = true; @@ -267,9 +276,7 @@ int MembersWidget::getListLeft() const { int MembersWidget::getListTop() const { int result = contentTop(); if (_limitReachedInfo) { - result += st::defaultLeftOutlineButton.padding.top(); result += _limitReachedInfo->height(); - result += st::defaultLeftOutlineButton.padding.bottom(); result += st::profileLimitReachedSkip; } return result; @@ -283,6 +290,7 @@ void MembersWidget::refreshMembers() { App::api()->requestFullPeer(chat); } fillChatMembers(chat); + refreshLimitReached(); } else if (auto megagroup = peer()->asMegagroup()) { checkSelfAdmin(megagroup); auto megagroupInfo = megagroup->mgInfo; @@ -296,6 +304,29 @@ void MembersWidget::refreshMembers() { refreshVisibility(); } +void MembersWidget::refreshLimitReached() { + auto chat = peer()->asChat(); + if (!chat) return; + + bool limitReachedShown = (_list.size() >= Global::ChatSizeMax()) && chat->amCreator(); + if (limitReachedShown && !_limitReachedInfo) { + _limitReachedInfo = new FlatLabel(this, st::profileLimitReachedLabel, st::profileLimitReachedStyle); + QString title = textRichPrepare(lng_profile_migrate_reached(lt_count, Global::ChatSizeMax())); + QString body = textRichPrepare(lang(lng_profile_migrate_body)); + QString link = textRichPrepare(lang(lng_profile_migrate_learn_more)); + QString text = qsl("%1%2%3\n%4 [a href=\"https://telegram.org/blog/supergroups5k\"]%5[/a]").arg(textcmdStartSemibold()).arg(title).arg(textcmdStopSemibold()).arg(body).arg(link); + _limitReachedInfo->setRichText(text); + _limitReachedInfo->setClickHandlerHook(func(this, &MembersWidget::limitReachedHook)); + } else if (!limitReachedShown && _limitReachedInfo) { + _limitReachedInfo.destroy(); + } +} + +bool MembersWidget::limitReachedHook(const ClickHandlerPtr &handler, Qt::MouseButton button) { + Ui::showLayer(new ConvertToSupergroupBox(peer()->asChat())); + return false; +} + void MembersWidget::checkSelfAdmin(ChatData *chat) { if (chat->participants.isEmpty()) return; @@ -481,8 +512,10 @@ MembersWidget::Member *MembersWidget::getMember(UserData *user) { } void MembersWidget::paintMember(Painter &p, int x, int y, Member *member, bool selected, bool selectedKick) { + int memberRowWidth = width() - x; if (selected) { - paintOutlinedRect(p, x, y, width() - x, st::profileMemberHeight); + accumulate_min(memberRowWidth, st::profileBlockWideWidthMax); + paintOutlinedRect(p, x, y, memberRowWidth, st::profileMemberHeight); } int skip = st::profileMemberPhotoPosition.x(); @@ -493,7 +526,7 @@ void MembersWidget::paintMember(Painter &p, int x, int y, Member *member, bool s } int nameLeft = x + st::profileMemberNamePosition.x(); int nameTop = y + st::profileMemberNamePosition.y(); - int nameWidth = width() - nameLeft - skip; + int nameWidth = memberRowWidth - st::profileMemberNamePosition.x() - skip; if (member->canBeKicked && selected) { p.setFont(selectedKick ? st::normalFont->underline() : st::normalFont); p.setPen(st::windowActiveTextFg); @@ -534,7 +567,12 @@ void MembersWidget::paintMember(Painter &p, int x, int y, Member *member, bool s } void MembersWidget::onKickConfirm() { - + Ui::hideLayer(); + if (auto chat = peer()->asChat()) { + App::main()->kickParticipant(chat, _kicking); + } else if (auto channel = peer()->asChannel()) { + App::api()->kickParticipant(channel, _kicking); + } } void MembersWidget::onUpdateOnlineDisplay() { diff --git a/Telegram/SourceFiles/profile/profile_members_widget.h b/Telegram/SourceFiles/profile/profile_members_widget.h index 8cd729244..45f717894 100644 --- a/Telegram/SourceFiles/profile/profile_members_widget.h +++ b/Telegram/SourceFiles/profile/profile_members_widget.h @@ -86,6 +86,9 @@ private: void updateOnlineCount(); void checkSelfAdmin(ChatData *chat); void checkSelfAdmin(ChannelData *megagroup); + void refreshLimitReached(); + + bool limitReachedHook(const ClickHandlerPtr &handler, Qt::MouseButton button); void refreshVisibility(); void updateSelection(); diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index e1bd58de1..4289a7b3d 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -431,6 +431,19 @@ void ChatData::setName(const QString &newName) { updateNameDelayed(newName.isEmpty() ? name : newName, QString(), QString()); } +void ChatData::invalidateParticipants() { + auto wasCanEdit = canEdit(); + participants = ChatData::Participants(); + admins = ChatData::Admins(); + flags &= ~MTPDchat::Flag::f_admin; + invitedByMe = ChatData::InvitedByMe(); + botStatus = 0; + if (wasCanEdit != canEdit()) { + Notify::peerUpdatedDelayed(this, Notify::PeerUpdate::Flag::ChatCanEdit); + } + Notify::peerUpdatedDelayed(this, Notify::PeerUpdate::Flag::MembersChanged | Notify::PeerUpdate::Flag::AdminsChanged); +} + void ChatData::setInviteLink(const QString &newInviteLink) { if (newInviteLink != _inviteLink) { _inviteLink = newInviteLink; diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 6432c00be..3b5cd7671 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -496,13 +496,7 @@ public: void setName(const QString &newName); - void invalidateParticipants() { - participants = ChatData::Participants(); - admins = ChatData::Admins(); - flags &= ~MTPDchat::Flag::f_admin; - invitedByMe = ChatData::InvitedByMe(); - botStatus = 0; - } + void invalidateParticipants(); bool noParticipantInfo() const { return (count > 0 || amIn()) && participants.isEmpty(); } diff --git a/Telegram/SourceFiles/ui/flatlabel.cpp b/Telegram/SourceFiles/ui/flatlabel.cpp index 195d8f3ec..3dc9a12f3 100644 --- a/Telegram/SourceFiles/ui/flatlabel.cpp +++ b/Telegram/SourceFiles/ui/flatlabel.cpp @@ -301,6 +301,8 @@ void FlatLabel::keyPressEvent(QKeyEvent *e) { } void FlatLabel::contextMenuEvent(QContextMenuEvent *e) { + if (!_selectable) return; + showContextMenu(e, ContextMenuReason::FromEvent); }