mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
Members block almost done in the new profile implementation.
Member kicking, upgrade to supergroup and testing is left.
This commit is contained in:
parent
91d516f18c
commit
ea8f01bd74
19 changed files with 779 additions and 116 deletions
|
@ -58,6 +58,7 @@ adaptiveWideWidth: 1366px;
|
|||
windowBg: #fff; // fallback for background: white
|
||||
windowTextFg: #000; // fallback for text color: black
|
||||
windowSubTextFg: #8a8a8a; // fallback for subtext color: gray
|
||||
windowActiveTextFg: #1485c2; // fallback for active color: blue online
|
||||
windowShadowFg: #000; // fallback for shadow color
|
||||
|
||||
wndMinHeight: 480px;
|
||||
|
@ -153,8 +154,8 @@ defaultLeftOutlineButton: OutlineButton {
|
|||
textBg: windowBg;
|
||||
textBgOver: #f2f7fa;
|
||||
|
||||
textFg: #1485c2;
|
||||
textFgOver: #1485c2;
|
||||
textFg: windowActiveTextFg;
|
||||
textFgOver: windowActiveTextFg;
|
||||
|
||||
font: normalFont;
|
||||
padding: margins(11px, 6px, 11px, 6px);
|
||||
|
|
|
@ -549,9 +549,15 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP
|
|||
if (newMembersCount > peer->membersCount()) {
|
||||
peer->setMembersCount(newMembersCount);
|
||||
}
|
||||
if (!bots && v.isEmpty()) {
|
||||
peer->setMembersCount(peer->mgInfo->lastParticipants.size());
|
||||
if (!bots) {
|
||||
if (v.isEmpty()) {
|
||||
peer->setMembersCount(peer->mgInfo->lastParticipants.size());
|
||||
}
|
||||
Notify::PeerUpdate update(peer);
|
||||
update.flags |= Notify::PeerUpdate::Flag::MembersChanged | Notify::PeerUpdate::Flag::AdminsChanged;
|
||||
Notify::peerUpdatedDelayed(update);
|
||||
}
|
||||
|
||||
peer->mgInfo->botStatus = botStatus;
|
||||
if (App::main()) emit fullPeerUpdated(peer);
|
||||
}
|
||||
|
@ -651,12 +657,14 @@ void ApiWrap::kickParticipantDone(KickRequest kick, const MTPUpdates &result, mt
|
|||
if (channel->adminsCount() > 1) {
|
||||
channel->setAdminsCount(channel->adminsCount() - 1);
|
||||
}
|
||||
Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::AdminsChanged);
|
||||
}
|
||||
megagroupInfo->bots.remove(kick.second);
|
||||
if (megagroupInfo->bots.isEmpty() && megagroupInfo->botStatus > 0) {
|
||||
megagroupInfo->botStatus = -1;
|
||||
}
|
||||
}
|
||||
Notify::peerUpdatedDelayed(kick.first, Notify::PeerUpdate::Flag::MembersChanged);
|
||||
emit fullPeerUpdated(kick.first);
|
||||
}
|
||||
|
||||
|
|
|
@ -223,11 +223,11 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
int32 onlineForSort(UserData *user, int32 now) {
|
||||
TimeId onlineForSort(UserData *user, TimeId now) {
|
||||
if (isServiceUser(user->id) || user->botInfo) {
|
||||
return -1;
|
||||
}
|
||||
int32 online = user->onlineTill;
|
||||
TimeId online = user->onlineTill;
|
||||
if (online <= 0) {
|
||||
switch (online) {
|
||||
case 0:
|
||||
|
@ -253,11 +253,14 @@ namespace {
|
|||
return online;
|
||||
}
|
||||
|
||||
int32 onlineWillChangeIn(UserData *user, int32 now) {
|
||||
int32 onlineWillChangeIn(UserData *user, TimeId now) {
|
||||
if (isServiceUser(user->id) || user->botInfo) {
|
||||
return 86400;
|
||||
}
|
||||
int32 online = user->onlineTill;
|
||||
return onlineWillChangeIn(user->onlineTill, now);
|
||||
}
|
||||
|
||||
int32 onlineWillChangeIn(TimeId online, TimeId now) {
|
||||
if (online <= 0) {
|
||||
if (-online > now) return -online - now;
|
||||
return 86400;
|
||||
|
@ -277,7 +280,7 @@ namespace {
|
|||
return dNow.secsTo(dTomorrow);
|
||||
}
|
||||
|
||||
QString onlineText(UserData *user, int32 now, bool precise) {
|
||||
QString onlineText(UserData *user, TimeId now, bool precise) {
|
||||
if (isNotificationsUser(user->id)) {
|
||||
return lang(lng_status_service_notifications);
|
||||
} else if (isServiceUser(user->id)) {
|
||||
|
@ -285,7 +288,10 @@ namespace {
|
|||
} else if (user->botInfo) {
|
||||
return lang(lng_status_bot);
|
||||
}
|
||||
int32 online = user->onlineTill;
|
||||
return onlineText(user->onlineTill, now, precise);
|
||||
}
|
||||
|
||||
QString onlineText(TimeId online, TimeId now, bool precise) {
|
||||
if (online <= 0) {
|
||||
switch (online) {
|
||||
case 0: return lang(lng_status_offline);
|
||||
|
@ -347,11 +353,14 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
bool onlineColorUse(UserData *user, int32 now) {
|
||||
bool onlineColorUse(UserData *user, TimeId now) {
|
||||
if (isServiceUser(user->id) || user->botInfo) {
|
||||
return false;
|
||||
}
|
||||
int32 online = user->onlineTill;
|
||||
return onlineColorUse(user->onlineTill, now);
|
||||
}
|
||||
|
||||
bool onlineColorUse(TimeId online, TimeId now) {
|
||||
if (online <= 0) {
|
||||
switch (online) {
|
||||
case 0:
|
||||
|
@ -394,12 +403,8 @@ namespace {
|
|||
status = &emptyStatus;
|
||||
data->contact = -1;
|
||||
|
||||
if (canShareThisContact != data->canShareThisContactFast()) {
|
||||
update.flags |= UpdateFlag::UserCanShareContact;
|
||||
}
|
||||
if (wasContact != data->isContact()) {
|
||||
update.flags |= UpdateFlag::UserIsContact;
|
||||
}
|
||||
if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact;
|
||||
if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact;
|
||||
} break;
|
||||
case mtpc_user: {
|
||||
const auto &d(user.c_user());
|
||||
|
@ -496,12 +501,8 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
if (canShareThisContact != data->canShareThisContactFast()) {
|
||||
update.flags |= UpdateFlag::UserCanShareContact;
|
||||
}
|
||||
if (wasContact != data->isContact()) {
|
||||
update.flags |= UpdateFlag::UserIsContact;
|
||||
}
|
||||
if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact;
|
||||
if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact;
|
||||
} break;
|
||||
}
|
||||
|
||||
|
@ -514,6 +515,8 @@ namespace {
|
|||
} else if (data->loadedStatus != PeerData::FullLoaded) {
|
||||
data->loadedStatus = PeerData::FullLoaded;
|
||||
}
|
||||
|
||||
auto oldOnlineTill = data->onlineTill;
|
||||
if (status && !minimal) switch (status->type()) {
|
||||
case mtpc_userStatusEmpty: data->onlineTill = 0; break;
|
||||
case mtpc_userStatusRecently:
|
||||
|
@ -526,6 +529,9 @@ namespace {
|
|||
case mtpc_userStatusOffline: data->onlineTill = status->c_userStatusOffline().vwas_online.v; break;
|
||||
case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break;
|
||||
}
|
||||
if (oldOnlineTill != data->onlineTill) {
|
||||
update.flags |= UpdateFlag::UserOnlineChanged;
|
||||
}
|
||||
|
||||
if (data->contact < 0 && !data->phone().isEmpty() && peerToUser(data->id) != MTP::authedId()) {
|
||||
data->contact = 0;
|
||||
|
@ -832,6 +838,7 @@ namespace {
|
|||
}
|
||||
} break;
|
||||
}
|
||||
Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged);
|
||||
if (chat && App::main()) {
|
||||
if (emitPeerUpdated) {
|
||||
App::main()->peerUpdated(chat);
|
||||
|
@ -878,6 +885,7 @@ namespace {
|
|||
chat->invalidateParticipants();
|
||||
chat->count++;
|
||||
}
|
||||
Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged);
|
||||
if (App::main()) {
|
||||
if (emitPeerUpdated) {
|
||||
App::main()->peerUpdated(chat);
|
||||
|
@ -894,6 +902,7 @@ 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);
|
||||
|
@ -944,6 +953,7 @@ namespace {
|
|||
chat->invalidateParticipants();
|
||||
chat->count--;
|
||||
}
|
||||
Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged);
|
||||
if (App::main()) {
|
||||
if (emitPeerUpdated) {
|
||||
App::main()->peerUpdated(chat);
|
||||
|
|
|
@ -59,10 +59,13 @@ namespace App {
|
|||
|
||||
QString formatPhone(QString phone);
|
||||
|
||||
int32 onlineForSort(UserData *user, int32 now);
|
||||
int32 onlineWillChangeIn(UserData *user, int32 nowOnServer);
|
||||
QString onlineText(UserData *user, int32 nowOnServer, bool precise = false);
|
||||
bool onlineColorUse(UserData *user, int32 now);
|
||||
TimeId onlineForSort(UserData *user, TimeId now);
|
||||
int32 onlineWillChangeIn(UserData *user, TimeId now);
|
||||
int32 onlineWillChangeIn(TimeId online, TimeId now);
|
||||
QString onlineText(UserData *user, TimeId now, bool precise = false);
|
||||
QString onlineText(TimeId online, TimeId now, bool precise = false);
|
||||
bool onlineColorUse(UserData *user, TimeId now);
|
||||
bool onlineColorUse(TimeId online, TimeId now);
|
||||
|
||||
UserData *feedUsers(const MTPVector<MTPUser> &users); // returns last user
|
||||
PeerData *feedChats(const MTPVector<MTPChat> &chats); // returns last chat
|
||||
|
|
|
@ -202,16 +202,20 @@ void ContactsInner::addAdminDone(const MTPUpdates &result, mtpRequestId req) {
|
|||
|
||||
_addAdminRequestId = 0;
|
||||
if (_addAdmin && _channel && _channel->isMegagroup()) {
|
||||
Notify::PeerUpdate update(_channel);
|
||||
if (_channel->mgInfo->lastParticipants.indexOf(_addAdmin) < 0) {
|
||||
_channel->mgInfo->lastParticipants.push_front(_addAdmin);
|
||||
update.flags |= Notify::PeerUpdate::Flag::MembersChanged;
|
||||
}
|
||||
_channel->mgInfo->lastAdmins.insert(_addAdmin);
|
||||
update.flags |= Notify::PeerUpdate::Flag::AdminsChanged;
|
||||
if (_addAdmin->botInfo) {
|
||||
_channel->mgInfo->bots.insert(_addAdmin);
|
||||
if (_channel->mgInfo->botStatus != 0 && _channel->mgInfo->botStatus < 2) {
|
||||
_channel->mgInfo->botStatus = 2;
|
||||
}
|
||||
}
|
||||
Notify::peerUpdatedDelayed(update);
|
||||
}
|
||||
if (_addAdminBox) _addAdminBox->onClose();
|
||||
emit adminAdded();
|
||||
|
@ -2176,6 +2180,8 @@ void MembersInner::membersReceived(const MTPchannels_ChannelParticipants &result
|
|||
_channel->mgInfo->lastAdmins.insert(_rows.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
Notify::peerUpdatedDelayed(_channel, Notify::PeerUpdate::Flag::AdminsChanged);
|
||||
}
|
||||
}
|
||||
if (_rows.isEmpty()) {
|
||||
|
|
|
@ -36,6 +36,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "apiwrap.h"
|
||||
#include "window/top_bar_widget.h"
|
||||
#include "playerwidget.h"
|
||||
#include "observer_peer.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -1056,6 +1057,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
|
|||
if (peer->asChannel()->mgInfo->lastParticipants.indexOf(user) < 0) {
|
||||
peer->asChannel()->mgInfo->lastParticipants.push_front(user);
|
||||
peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated;
|
||||
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
|
||||
}
|
||||
if (user->botInfo) {
|
||||
peer->asChannel()->mgInfo->bots.insert(user);
|
||||
|
@ -1074,6 +1076,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
|
|||
if (result->from()->isUser()) {
|
||||
if (peer->asChannel()->mgInfo->lastParticipants.indexOf(result->from()->asUser()) < 0) {
|
||||
peer->asChannel()->mgInfo->lastParticipants.push_front(result->from()->asUser());
|
||||
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
|
||||
}
|
||||
if (result->from()->asUser()->botInfo) {
|
||||
peer->asChannel()->mgInfo->bots.insert(result->from()->asUser());
|
||||
|
@ -1105,6 +1108,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
|
|||
int32 index = megagroupInfo->lastParticipants.indexOf(user);
|
||||
if (index >= 0) {
|
||||
megagroupInfo->lastParticipants.removeAt(index);
|
||||
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
|
||||
}
|
||||
if (peer->asChannel()->membersCount() > 1) {
|
||||
peer->asChannel()->setMembersCount(channel->membersCount() - 1);
|
||||
|
@ -1117,6 +1121,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
|
|||
if (channel->adminsCount() > 1) {
|
||||
channel->setAdminsCount(channel->adminsCount() - 1);
|
||||
}
|
||||
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::AdminsChanged);
|
||||
}
|
||||
megagroupInfo->bots.remove(user);
|
||||
if (megagroupInfo->bots.isEmpty() && megagroupInfo->botStatus > 0) {
|
||||
|
@ -1328,6 +1333,9 @@ HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
|
|||
if (prev) {
|
||||
lastAuthors->push_front(adding->from()->asUser());
|
||||
}
|
||||
if (peer->isMegagroup()) {
|
||||
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (adding->definesReplyKeyboard()) {
|
||||
|
@ -1520,6 +1528,7 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
|||
lastAuthors->push_back(item->from()->asUser());
|
||||
if (peer->isMegagroup()) {
|
||||
peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated;
|
||||
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1681,7 +1681,6 @@ void MainWidget::onParentResize(const QSize &newSize) {
|
|||
void MainWidget::updateOnlineDisplay() {
|
||||
if (this != App::main()) return;
|
||||
_history->updateOnlineDisplay(_history->x(), width() - _history->x() - st::sysBtnDelta * 2 - st::sysCls.img.pxWidth() - st::sysRes.img.pxWidth() - st::sysMin.img.pxWidth());
|
||||
// if (_profile) _profile->updateOnlineDisplay(); TODO
|
||||
if (App::wnd()->settingsWidget()) App::wnd()->settingsWidget()->updateOnlineDisplay();
|
||||
}
|
||||
|
||||
|
@ -3790,7 +3789,10 @@ void MainWidget::updateOnline(bool gotOtherOffline) {
|
|||
_lastSetOnline = ms;
|
||||
_onlineRequest = MTP::send(MTPaccount_UpdateStatus(MTP_bool(!isOnline)));
|
||||
|
||||
if (App::self()) App::self()->onlineTill = unixtime() + (isOnline ? (Global::OnlineUpdatePeriod() / 1000) : -1);
|
||||
if (App::self()) {
|
||||
App::self()->onlineTill = unixtime() + (isOnline ? (Global::OnlineUpdatePeriod() / 1000) : -1);
|
||||
Notify::peerUpdatedDelayed(App::self(), Notify::PeerUpdate::Flag::UserOnlineChanged);
|
||||
}
|
||||
|
||||
_lastSetOnline = getms(true);
|
||||
|
||||
|
@ -4280,6 +4282,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
|||
case mtpc_userStatusOnline: user->onlineTill = d.vstatus.c_userStatusOnline().vexpires.v; break;
|
||||
}
|
||||
App::markPeerUpdated(user);
|
||||
Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserOnlineChanged);
|
||||
}
|
||||
if (d.vuser_id.v == MTP::authedId()) {
|
||||
if (d.vstatus.type() == mtpc_userStatusOffline || d.vstatus.type() == mtpc_userStatusEmpty) {
|
||||
|
|
|
@ -51,6 +51,7 @@ struct PeerUpdate {
|
|||
UserPhoneChanged = 0x00040000U,
|
||||
UserIsBlocked = 0x00080000U,
|
||||
BotCommandsChanged = 0x00100000U,
|
||||
UserOnlineChanged = 0x00200000U,
|
||||
|
||||
ChatCanEdit = 0x00010000U,
|
||||
|
||||
|
|
|
@ -56,14 +56,15 @@ profileStatusFont: normalFont;
|
|||
profileStatusFg: windowSubTextFg;
|
||||
profileMarginBottom: 30px;
|
||||
|
||||
profileActiveBg: #3fb0e4;
|
||||
profileButtonLeft: 27px;
|
||||
profileButtonTop: 88px;
|
||||
profileButtonSkip: 10px;
|
||||
profilePrimaryButton: BoxButton {
|
||||
textFg: #ffffff;
|
||||
textFgOver: #ffffff;
|
||||
textBg: #3fb0e4;
|
||||
textBgOver: #3fb0e4;
|
||||
textBg: profileActiveBg;
|
||||
textBgOver: profileActiveBg;
|
||||
|
||||
width: -34px;
|
||||
height: 34px;
|
||||
|
@ -80,7 +81,7 @@ profileSecondaryButton: BoxButton(profilePrimaryButton) {
|
|||
textBgOver: #f2f7fa;
|
||||
}
|
||||
profileAddMemberIcon: icon {
|
||||
{ "profile_add_member", #3fb0e4, point(20px, 10px) },
|
||||
{ "profile_add_member", profileActiveBg, point(20px, 10px) },
|
||||
};
|
||||
profileAddMemberButton: BoxButton(profileSecondaryButton) {
|
||||
width: 62px;
|
||||
|
@ -88,7 +89,7 @@ profileAddMemberButton: BoxButton(profileSecondaryButton) {
|
|||
}
|
||||
|
||||
profileDropAreaBg: profileBg;
|
||||
profileDropAreaFg: #3fb0e4;
|
||||
profileDropAreaFg: profileActiveBg;
|
||||
profileDropAreaPadding: margins(25px, 3px, 25px, 20px);
|
||||
profileDropAreaTitleFont: font(24px);
|
||||
profileDropAreaTitleTop: 30px;
|
||||
|
@ -113,13 +114,13 @@ profileBlockLeftMax: 25px;
|
|||
profileBlockNarrowWidthMin: 220px;
|
||||
profileBlockWideWidthMin: 300px;
|
||||
profileBlockWideWidthMax: 340px;
|
||||
profileBlockMarginTop: 21px;
|
||||
profileBlockMarginTop: 14px;
|
||||
profileBlockMarginRight: 10px;
|
||||
profileBlockMarginBottom: 4px;
|
||||
profileBlockTitleHeight: 22px;
|
||||
profileBlockTitleHeight: 25px;
|
||||
profileBlockTitleFont: font(14px semibold);
|
||||
profileBlockTitleFg: black;
|
||||
profileBlockTitlePosition: point(24px, -7px);
|
||||
profileBlockTitlePosition: point(24px, 0px);
|
||||
profileBlockLabel: flatLabel(labelDefFlat) {
|
||||
textFg: windowSubTextFg;
|
||||
}
|
||||
|
@ -137,3 +138,19 @@ profileBlockOneLineWidthMax: 240px;
|
|||
profileInviteLinkText: flatLabel(profileBlockTextPart) {
|
||||
width: 1px; // Required for BreakEverywhere
|
||||
}
|
||||
|
||||
profileLimitReachedSkip: 6px;
|
||||
|
||||
profileMemberHeight: 58px;
|
||||
profileMemberPaddingLeft: 16px;
|
||||
profileMemberPhotoSize: 46px;
|
||||
profileMemberPhotoPosition: point(12px, 6px);
|
||||
profileMemberNamePosition: point(68px, 11px);
|
||||
profileMemberNameFg: windowTextFg;
|
||||
profileMemberStatusPosition: point(68px, 31px);
|
||||
profileMemberStatusFg: windowSubTextFg;
|
||||
profileMemberStatusFgOver: windowSubTextFg;
|
||||
profileMemberStatusFgActive: windowActiveTextFg;
|
||||
profileMemberAdminIcon: icon {
|
||||
{ "profile_admin_star", profileActiveBg, point(4px, 2px) },
|
||||
};
|
||||
|
|
|
@ -77,7 +77,6 @@ void ActionsWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
|
|||
|
||||
void ActionsWidget::validateBlockStatus() const {
|
||||
auto needFullPeer = [this]() {
|
||||
return true;
|
||||
if (auto user = peer()->asUser()) {
|
||||
if (user->blockStatus() == UserData::BlockStatus::Unknown) {
|
||||
return true;
|
||||
|
|
|
@ -37,6 +37,9 @@ public:
|
|||
virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||
}
|
||||
|
||||
virtual ~BlockWidget() {
|
||||
}
|
||||
|
||||
signals:
|
||||
void heightUpdated();
|
||||
|
||||
|
|
|
@ -38,33 +38,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
namespace Profile {
|
||||
namespace {
|
||||
|
||||
class OnlineCounter {
|
||||
public:
|
||||
OnlineCounter() : _currentTime(unixtime()), _self(App::self()) {
|
||||
}
|
||||
void feedUser(UserData *user) {
|
||||
if (App::onlineForSort(user, _currentTime) > _currentTime) {
|
||||
++_result;
|
||||
if (user != _self) {
|
||||
_onlyMe = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
QString result(int fullCount) const {
|
||||
if (_result > 0 && !_onlyMe) {
|
||||
return lng_chat_status_members_online(lt_count, fullCount, lt_count_online, _result);
|
||||
}
|
||||
return lng_chat_status_members(lt_count, fullCount);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _onlyMe = true;
|
||||
int _result = 0;
|
||||
int _currentTime;
|
||||
UserData *_self;
|
||||
|
||||
};
|
||||
|
||||
using UpdateFlag = Notify::PeerUpdate::Flag;
|
||||
const auto ButtonsUpdateFlags = UpdateFlag::UserCanShareContact
|
||||
| UpdateFlag::ChatCanEdit
|
||||
|
@ -345,27 +318,17 @@ void CoverWidget::refreshStatusText() {
|
|||
if (_peerUser) {
|
||||
_statusText = App::onlineText(_peerUser, currentTime, true);
|
||||
} else if (_peerChat && _peerChat->amIn()) {
|
||||
if (_peerChat->noParticipantInfo()) {
|
||||
App::api()->requestFullPeer(_peer);
|
||||
if (_statusText.isEmpty()) {
|
||||
_statusText = lng_chat_status_members(lt_count, _peerChat->count);
|
||||
}
|
||||
int fullCount = qMax(_peerChat->count, _peerChat->participants.size());
|
||||
if (_onlineCount > 0 && _onlineCount <= fullCount) {
|
||||
_statusText = lng_chat_status_members_online(lt_count, fullCount, lt_count_online, _onlineCount);
|
||||
} else {
|
||||
OnlineCounter counter;
|
||||
auto &participants = _peerChat->participants;
|
||||
for (auto i = participants.cbegin(), e = participants.cend(); i != e; ++i) {
|
||||
counter.feedUser(i.key());
|
||||
}
|
||||
_statusText = counter.result(participants.size());
|
||||
_statusText = lng_chat_status_members(lt_count, _peerChat->count);
|
||||
}
|
||||
} else if (isUsingMegagroupOnlineCount()) {
|
||||
OnlineCounter counter;
|
||||
for_const (auto user, _peerMegagroup->mgInfo->lastParticipants) {
|
||||
counter.feedUser(user);
|
||||
}
|
||||
_statusText = counter.result(_peerMegagroup->membersCount());
|
||||
} else if (_peerChannel) {
|
||||
if (_peerChannel->membersCount() > 0) {
|
||||
int fullCount = _peerChannel->membersCount();
|
||||
if (_onlineCount > 0 && _onlineCount <= fullCount) {
|
||||
_statusText = lng_chat_status_members_online(lt_count, fullCount, lt_count_online, _onlineCount);
|
||||
} else if (fullCount > 0 ) {
|
||||
_statusText = lng_chat_status_members(lt_count, _peerChannel->membersCount());
|
||||
} else {
|
||||
_statusText = lang(_peerChannel->isMegagroup() ? lng_group_status : lng_channel_status);
|
||||
|
@ -376,23 +339,6 @@ void CoverWidget::refreshStatusText() {
|
|||
update();
|
||||
}
|
||||
|
||||
bool CoverWidget::isUsingMegagroupOnlineCount() const {
|
||||
if (!_peerMegagroup || !_peerMegagroup->amIn()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_peerMegagroup->membersCount() <= 0 || _peerMegagroup->membersCount() > Global::ChatSizeMax()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_peerMegagroup->mgInfo->lastParticipants.isEmpty() || _peerMegagroup->lastParticipantsCountOutdated()) {
|
||||
App::api()->requestLastParticipants(_peerMegagroup);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CoverWidget::refreshButtons() {
|
||||
clearButtons();
|
||||
if (_peerUser) {
|
||||
|
@ -422,8 +368,12 @@ void CoverWidget::setChatButtons() {
|
|||
}
|
||||
|
||||
void CoverWidget::setMegagroupButtons() {
|
||||
if (_peerMegagroup->canEditPhoto()) {
|
||||
addButton(lang(lng_profile_set_group_photo), SLOT(onSetPhoto()));
|
||||
if (_peerMegagroup->amIn()) {
|
||||
if (_peerMegagroup->canEditPhoto()) {
|
||||
addButton(lang(lng_profile_set_group_photo), SLOT(onSetPhoto()));
|
||||
}
|
||||
} else {
|
||||
addButton(lang(lng_profile_join_channel), SLOT(onJoin()));
|
||||
}
|
||||
if (_peerMegagroup->canAddMembers()) {
|
||||
addButton(lang(lng_profile_add_participant), SLOT(onAddMember()), &st::profileAddMemberButton);
|
||||
|
@ -463,6 +413,11 @@ void CoverWidget::addButton(const QString &text, const char *slot, const style::
|
|||
_buttons.push_back({ button, replacement });
|
||||
}
|
||||
|
||||
void CoverWidget::onOnlineCountUpdated(int onlineCount) {
|
||||
_onlineCount = onlineCount;
|
||||
refreshStatusText();
|
||||
}
|
||||
|
||||
void CoverWidget::onSendMessage() {
|
||||
Ui::showPeerHistory(_peer, ShowAtUnreadMsgId);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,9 @@ public:
|
|||
// It should show it only if it is hidden in the cover.
|
||||
bool shareContactButtonShown() const;
|
||||
|
||||
public slots:
|
||||
void onOnlineCountUpdated(int onlineCount);
|
||||
|
||||
private slots:
|
||||
void onPhotoShow();
|
||||
|
||||
|
@ -83,7 +86,6 @@ private:
|
|||
void moveAndToggleButtons(int newWiddth);
|
||||
void refreshNameText();
|
||||
void refreshStatusText();
|
||||
bool isUsingMegagroupOnlineCount() const;
|
||||
|
||||
void refreshButtons();
|
||||
void setUserButtons();
|
||||
|
@ -125,6 +127,8 @@ private:
|
|||
int _photoLeft = 0; // Caching countPhotoLeft() result.
|
||||
int _dividerTop = 0;
|
||||
|
||||
int _onlineCount = 0;
|
||||
|
||||
FileDialog::QueryId _setPhotoFileQueryId = 0;
|
||||
|
||||
};
|
||||
|
|
|
@ -59,7 +59,10 @@ void InnerWidget::createBlocks() {
|
|||
}
|
||||
_blocks.push_back({ new ActionsWidget(this, _peer), BlockSide::Right });
|
||||
if (chat || megagroup) {
|
||||
_blocks.push_back({ new MembersWidget(this, _peer), BlockSide::Left });
|
||||
auto membersWidget = new MembersWidget(this, _peer);
|
||||
connect(membersWidget, SIGNAL(onlineCountUpdated(int)), _cover, SLOT(onOnlineCountUpdated(int)));
|
||||
_cover->onOnlineCountUpdated(membersWidget->onlineCount());
|
||||
_blocks.push_back({ membersWidget, BlockSide::Left });
|
||||
}
|
||||
for_const (auto &blockData, _blocks) {
|
||||
connect(blockData.block, SIGNAL(heightUpdated()), this, SLOT(onBlockHeightUpdated()));
|
||||
|
@ -81,11 +84,9 @@ void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
|||
decreaseAdditionalHeight(notDisplayedAtBottom);
|
||||
}
|
||||
|
||||
//loadProfilePhotos(_visibleTop);
|
||||
if (peer()->isMegagroup() && !peer()->asChannel()->mgInfo->lastParticipants.isEmpty() && peer()->asChannel()->mgInfo->lastParticipants.size() < peer()->asChannel()->membersCount()) {
|
||||
if (_visibleTop + (PreloadHeightsCount + 1) * (_visibleBottom - _visibleTop) > height()) {
|
||||
App::api()->requestLastParticipants(peer()->asChannel(), false);
|
||||
}
|
||||
for_const (auto blockData, _blocks) {
|
||||
int blockY = blockData.block->y();
|
||||
blockData.block->setVisibleTopBottom(visibleTop - blockY, visibleBottom - blockY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,11 +110,11 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
|||
if (_mode == Mode::TwoColumn) {
|
||||
int leftHeight = countBlocksHeight(BlockSide::Left);
|
||||
int rightHeight = countBlocksHeight(BlockSide::Right);
|
||||
int minHeight = qMin(leftHeight, rightHeight);
|
||||
int shadowHeight = rightHeight;// qMin(leftHeight, rightHeight);
|
||||
|
||||
int shadowLeft = _blocksLeft + _leftColumnWidth + _columnDivider;
|
||||
int shadowTop = _blocksTop + st::profileBlockMarginTop;
|
||||
p.fillRect(rtlrect(shadowLeft, shadowTop, st::lineWidth, minHeight - st::profileBlockMarginTop, width()), st::shadowColor);
|
||||
p.fillRect(rtlrect(shadowLeft, shadowTop, st::lineWidth, shadowHeight - st::profileBlockMarginTop, width()), st::shadowColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,7 +217,7 @@ int InnerWidget::resizeGetHeight(int newWidth) {
|
|||
|
||||
_blocksTop = _cover->y() + _cover->height() + st::profileBlocksTop;
|
||||
_blocksLeft = countBlocksLeft(newWidth);
|
||||
_columnDivider = _blocksLeft;
|
||||
_columnDivider = st::profileMemberPaddingLeft;
|
||||
_mode = countBlocksMode(newWidth);
|
||||
_leftColumnWidth = countLeftColumnWidth(newWidth);
|
||||
resizeBlocks(newWidth);
|
||||
|
|
|
@ -22,8 +22,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "profile/profile_members_widget.h"
|
||||
|
||||
#include "styles/style_profile.h"
|
||||
#include "mtproto/file_download.h"
|
||||
#include "ui/buttons/left_outline_button.h"
|
||||
#include "ui/flatlabel.h"
|
||||
#include "boxes/contactsbox.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "apiwrap.h"
|
||||
#include "observer_peer.h"
|
||||
#include "lang.h"
|
||||
|
||||
|
@ -31,17 +35,540 @@ namespace Profile {
|
|||
|
||||
using UpdateFlag = Notify::PeerUpdate::Flag;
|
||||
|
||||
MembersWidget::MembersWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_participants_section))
|
||||
{
|
||||
show();
|
||||
MembersWidget::MembersWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_participants_section)) {
|
||||
setMouseTracking(true);
|
||||
|
||||
_removeWidth = st::normalFont->width(lang(lng_profile_kick));
|
||||
|
||||
_updateOnlineTimer.setSingleShot(true);
|
||||
connect(&_updateOnlineTimer, SIGNAL(timeout()), this, SLOT(onUpdateOnlineDisplay()));
|
||||
|
||||
auto observeEvents = UpdateFlag::AdminsChanged | UpdateFlag::MembersChanged | UpdateFlag::UserOnlineChanged;
|
||||
Notify::registerPeerObserver(observeEvents, this, &MembersWidget::notifyPeerUpdated);
|
||||
FileDownload::registerImageLoadedObserver(this, &MembersWidget::repaintCallback);
|
||||
|
||||
refreshMembers();
|
||||
}
|
||||
|
||||
void MembersWidget::repaintCallback() {
|
||||
update();
|
||||
}
|
||||
|
||||
void MembersWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
|
||||
if (update.peer != peer()) {
|
||||
if (update.flags & UpdateFlag::UserOnlineChanged) {
|
||||
if (auto user = update.peer->asUser()) {
|
||||
refreshUserOnline(user);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (update.flags & UpdateFlag::MembersChanged) {
|
||||
refreshMembers();
|
||||
contentSizeUpdated();
|
||||
} else if (update.flags & UpdateFlag::AdminsChanged) {
|
||||
if (auto chat = peer()->asChat()) {
|
||||
for_const (auto member, _list) {
|
||||
setMemberFlags(member, chat);
|
||||
}
|
||||
} else if (auto megagroup = peer()->asMegagroup()) {
|
||||
for_const (auto member, _list) {
|
||||
setMemberFlags(member, megagroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
repaintCallback();
|
||||
}
|
||||
|
||||
void MembersWidget::refreshUserOnline(UserData *user) {
|
||||
auto it = _membersByUser.find(user);
|
||||
if (it == _membersByUser.cend()) return;
|
||||
|
||||
_now = unixtime();
|
||||
|
||||
auto member = it.value();
|
||||
member->online = !user->botInfo && App::onlineColorUse(user->onlineTill, _now);
|
||||
member->onlineTill = user->onlineTill;
|
||||
member->onlineForSort = user->isSelf() ? INT_MAX : App::onlineForSort(user, _now);
|
||||
member->onlineText = QString();
|
||||
|
||||
sortMembers();
|
||||
update();
|
||||
}
|
||||
|
||||
void MembersWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||
_visibleTop = visibleTop;
|
||||
_visibleBottom = visibleBottom;
|
||||
|
||||
if (auto megagroup = peer()->asMegagroup()) {
|
||||
auto megagroupInfo = megagroup->mgInfo;
|
||||
if (!megagroupInfo->lastParticipants.isEmpty() && megagroupInfo->lastParticipants.size() < megagroup->membersCount()) {
|
||||
if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop) > height()) {
|
||||
App::api()->requestLastParticipants(megagroup, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preloadUserPhotos();
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
int MembersWidget::resizeGetHeight(int newWidth) {
|
||||
int newHeight = contentTop();
|
||||
|
||||
if (_limitReachedInfo) {
|
||||
int limitReachedInfoWidth = newWidth - getListLeft();
|
||||
_limitReachedInfo->resizeToWidth(limitReachedInfoWidth);
|
||||
newHeight = getListTop();
|
||||
}
|
||||
|
||||
newHeight += _list.size() * st::profileMemberHeight;
|
||||
|
||||
return newHeight;
|
||||
}
|
||||
|
||||
void MembersWidget::paintContents(Painter &p) {
|
||||
int left = getListLeft();
|
||||
int top = getListTop();
|
||||
if (_limitReachedInfo) {
|
||||
int infoTop = contentTop();
|
||||
int infoHeight = top - infoTop - st::profileLimitReachedSkip;
|
||||
paintOutlinedRect(p, left, infoTop, width() - left, infoHeight);
|
||||
}
|
||||
|
||||
_now = unixtime();
|
||||
int from = floorclamp(_visibleTop - top, st::profileMemberHeight, 0, _list.size());
|
||||
int to = ceilclamp(_visibleBottom - top, st::profileMemberHeight, 0, _list.size());
|
||||
for (int i = from; i < to; ++i) {
|
||||
int y = top + i * st::profileMemberHeight;
|
||||
bool selected = (i == _selected);
|
||||
bool selectedKick = selected && _selectedKick;
|
||||
if (_pressed >= 0) {
|
||||
if (_pressed != _selected) {
|
||||
selected = selectedKick = false;
|
||||
} else if (!_pressedKick) {
|
||||
_selectedKick = false;
|
||||
}
|
||||
}
|
||||
paintMember(p, left, y, _list.at(i), selected, selectedKick);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersWidget::paintOutlinedRect(Painter &p, int x, int y, int w, int h) const {
|
||||
int outlineWidth = st::defaultLeftOutlineButton.outlineWidth;
|
||||
p.fillRect(rtlrect(x, y, outlineWidth, h, width()), st::defaultLeftOutlineButton.outlineFgOver);
|
||||
p.fillRect(rtlrect(x + outlineWidth, y, w - outlineWidth, h, width()), st::defaultLeftOutlineButton.textBgOver);
|
||||
}
|
||||
|
||||
void MembersWidget::mouseMoveEvent(QMouseEvent *e) {
|
||||
_mousePosition = e->globalPos();
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
void MembersWidget::mousePressEvent(QMouseEvent *e) {
|
||||
_mousePosition = e->globalPos();
|
||||
updateSelection();
|
||||
|
||||
_pressed = _selected;
|
||||
_pressedKick = _selectedKick;
|
||||
}
|
||||
|
||||
void MembersWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_mousePosition = e->globalPos();
|
||||
updateSelection();
|
||||
|
||||
auto pressed = _pressed;
|
||||
auto pressedKick = _pressedKick;
|
||||
_pressed = -1;
|
||||
_pressedKick = false;
|
||||
if (pressed >= 0 && pressed < _list.size() && pressed == _selected && pressedKick == _selectedKick) {
|
||||
auto member = _list.at(pressed);
|
||||
if (pressedKick) {
|
||||
_kicking = member->user;
|
||||
ConfirmBox *box = new ConfirmBox(lng_profile_sure_kick(lt_user, _kicking->firstName), lang(lng_box_remove));
|
||||
connect(box, SIGNAL(confirmed()), this, SLOT(onKickConfirm()));
|
||||
Ui::showLayer(box);
|
||||
} else {
|
||||
Ui::showPeerProfile(member->user);
|
||||
}
|
||||
}
|
||||
setCursor(_selectedKick ? style::cur_pointer : style::cur_default);
|
||||
repaintSelectedRow();
|
||||
}
|
||||
|
||||
void MembersWidget::enterEvent(QEvent *e) {
|
||||
_mousePosition = QCursor::pos();
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
void MembersWidget::leaveEvent(QEvent *e) {
|
||||
_mousePosition = QPoint(-1, -1);
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
void MembersWidget::updateSelection() {
|
||||
int selected = -1;
|
||||
bool selectedKick = false;
|
||||
|
||||
auto mouse = mapFromGlobal(_mousePosition);
|
||||
if (rtl()) mouse.setX(width() - mouse.x());
|
||||
int left = getListLeft();
|
||||
int top = getListTop();
|
||||
if (mouse.x() >= left && mouse.x() < width() && mouse.y() >= top) {
|
||||
selected = (mouse.y() - top) / st::profileMemberHeight;
|
||||
if (selected >= _list.size()) {
|
||||
selected = -1;
|
||||
} else if (_list.at(selected)->canBeKicked) {
|
||||
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;
|
||||
if (mouse.x() >= nameLeft + nameWidth - _removeWidth && mouse.x() < nameLeft + nameWidth) {
|
||||
if (mouse.y() >= nameTop && mouse.y() < nameTop + st::normalFont->height) {
|
||||
selectedKick = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSelected(selected, selectedKick);
|
||||
}
|
||||
|
||||
void MembersWidget::setSelected(int selected, bool selectedKick) {
|
||||
if (_selected == selected && _selectedKick == selectedKick) {
|
||||
return;
|
||||
}
|
||||
|
||||
repaintSelectedRow();
|
||||
if (_selectedKick != selectedKick) {
|
||||
_selectedKick = selectedKick;
|
||||
if (_pressed < 0) {
|
||||
setCursor(_selectedKick ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
}
|
||||
if (_selected != selected) {
|
||||
_selected = selected;
|
||||
repaintSelectedRow();
|
||||
}
|
||||
}
|
||||
|
||||
void MembersWidget::repaintSelectedRow() {
|
||||
if (_selected >= 0) {
|
||||
int left = getListLeft();
|
||||
rtlupdate(left, getListTop() + _selected * st::profileMemberHeight, width() - left, st::profileMemberHeight);
|
||||
}
|
||||
}
|
||||
|
||||
int MembersWidget::getListLeft() const {
|
||||
return st::profileBlockTitlePosition.x() - st::profileMemberPaddingLeft;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void MembersWidget::refreshMembers() {
|
||||
_now = unixtime();
|
||||
if (auto chat = peer()->asChat()) {
|
||||
checkSelfAdmin(chat);
|
||||
if (chat->noParticipantInfo()) {
|
||||
App::api()->requestFullPeer(chat);
|
||||
}
|
||||
fillChatMembers(chat);
|
||||
} else if (auto megagroup = peer()->asMegagroup()) {
|
||||
checkSelfAdmin(megagroup);
|
||||
auto megagroupInfo = megagroup->mgInfo;
|
||||
if (megagroupInfo->lastParticipants.isEmpty() || megagroup->lastParticipantsCountOutdated()) {
|
||||
App::api()->requestLastParticipants(megagroup);
|
||||
}
|
||||
fillMegagroupMembers(megagroup);
|
||||
}
|
||||
sortMembers();
|
||||
|
||||
refreshVisibility();
|
||||
}
|
||||
|
||||
void MembersWidget::checkSelfAdmin(ChatData *chat) {
|
||||
if (chat->participants.isEmpty()) return;
|
||||
|
||||
auto self = App::self();
|
||||
if (chat->amAdmin() && !chat->admins.contains(self)) {
|
||||
chat->admins.insert(self);
|
||||
} else if (!chat->amAdmin() && chat->admins.contains(self)) {
|
||||
chat->admins.remove(self);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersWidget::checkSelfAdmin(ChannelData *megagroup) {
|
||||
if (megagroup->mgInfo->lastParticipants.isEmpty()) return;
|
||||
|
||||
bool amAdmin = (megagroup->amCreator() || megagroup->amEditor());
|
||||
auto self = App::self();
|
||||
if (amAdmin && !megagroup->mgInfo->lastAdmins.contains(self)) {
|
||||
megagroup->mgInfo->lastAdmins.insert(self);
|
||||
} else if (!amAdmin && megagroup->mgInfo->lastAdmins.contains(self)) {
|
||||
megagroup->mgInfo->lastAdmins.remove(self);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersWidget::preloadUserPhotos() {
|
||||
int top = getListTop();
|
||||
int preloadFor = (_visibleBottom - _visibleTop) * PreloadHeightsCount;
|
||||
int from = floorclamp(_visibleTop - top, st::profileMemberHeight, 0, _list.size());
|
||||
int to = ceilclamp(_visibleBottom + preloadFor - top, st::profileMemberHeight, 0, _list.size());
|
||||
for (int i = from; i < to; ++i) {
|
||||
_list.at(i)->user->loadUserpic();
|
||||
}
|
||||
}
|
||||
|
||||
void MembersWidget::refreshVisibility() {
|
||||
setVisible(!_list.isEmpty());
|
||||
}
|
||||
|
||||
void MembersWidget::sortMembers() {
|
||||
if (!_sortByOnline || _list.isEmpty()) return;
|
||||
|
||||
qSort(_list.begin(), _list.end(), [](Member *a, Member *b) -> bool {
|
||||
return a->onlineForSort > b->onlineForSort;
|
||||
});
|
||||
|
||||
updateOnlineCount();
|
||||
}
|
||||
|
||||
void MembersWidget::updateOnlineCount() {
|
||||
bool onlyMe = true;
|
||||
int newOnlineCount = 0;
|
||||
for_const (auto member, _list) {
|
||||
bool isOnline = !member->user->botInfo && App::onlineColorUse(member->onlineTill, _now);
|
||||
if (member->online != isOnline) {
|
||||
member->online = isOnline;
|
||||
member->onlineText = QString();
|
||||
}
|
||||
if (member->online) {
|
||||
++newOnlineCount;
|
||||
if (!member->user->isSelf()) {
|
||||
onlyMe = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newOnlineCount == 1 && onlyMe) {
|
||||
newOnlineCount = 0;
|
||||
}
|
||||
if (_onlineCount != newOnlineCount) {
|
||||
_onlineCount = newOnlineCount;
|
||||
emit onlineCountUpdated(_onlineCount);
|
||||
}
|
||||
}
|
||||
|
||||
MembersWidget::Member *MembersWidget::addUser(ChatData *chat, UserData *user) {
|
||||
auto member = getMember(user);
|
||||
setMemberFlags(member, chat);
|
||||
_list.push_back(member);
|
||||
return member;
|
||||
}
|
||||
|
||||
void MembersWidget::fillChatMembers(ChatData *chat) {
|
||||
if (chat->participants.isEmpty()) return;
|
||||
|
||||
_list.clear();
|
||||
if (!chat->amIn()) return;
|
||||
|
||||
_sortByOnline = true;
|
||||
|
||||
_list.reserve(chat->participants.size());
|
||||
addUser(chat, App::self())->onlineForSort = INT_MAX; // Put me on the first place.
|
||||
for (auto i = chat->participants.cbegin(), e = chat->participants.cend(); i != e; ++i) {
|
||||
auto user = i.key();
|
||||
if (!user->isSelf()) {
|
||||
addUser(chat, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MembersWidget::setMemberFlags(Member *member, ChatData *chat) {
|
||||
if (member->user->id == peerFromUser(MTP::authedId())) {
|
||||
member->canBeKicked = false;
|
||||
} else if (chat->amCreator() || (chat->amAdmin() && !member->isAdmin)) {
|
||||
member->canBeKicked = true;
|
||||
} else {
|
||||
member->canBeKicked = chat->invitedByMe.contains(member->user);
|
||||
}
|
||||
member->isAdmin = chat->admins.contains(member->user);
|
||||
}
|
||||
|
||||
MembersWidget::Member *MembersWidget::addUser(ChannelData *megagroup, UserData *user) {
|
||||
auto member = getMember(user);
|
||||
setMemberFlags(member, megagroup);
|
||||
_list.push_back(member);
|
||||
return member;
|
||||
}
|
||||
|
||||
void MembersWidget::fillMegagroupMembers(ChannelData *megagroup) {
|
||||
t_assert(megagroup->mgInfo != nullptr);
|
||||
if (megagroup->mgInfo->lastParticipants.isEmpty()) return;
|
||||
|
||||
if (!megagroup->amIn()) {
|
||||
_list.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
_sortByOnline = (megagroup->membersCount() > 0 && megagroup->membersCount() <= Global::ChatSizeMax());
|
||||
|
||||
auto &membersList = megagroup->mgInfo->lastParticipants;
|
||||
if (_sortByOnline) {
|
||||
_list.clear();
|
||||
_list.reserve(membersList.size());
|
||||
addUser(megagroup, App::self())->onlineForSort = INT_MAX;
|
||||
} else if (membersList.size() >= _list.size()) {
|
||||
if (addUsersToEnd(megagroup)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!_sortByOnline) {
|
||||
_list.clear();
|
||||
_list.reserve(membersList.size());
|
||||
}
|
||||
for_const (auto user, membersList) {
|
||||
if (!_sortByOnline || !user->isSelf()) {
|
||||
addUser(megagroup, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MembersWidget::addUsersToEnd(ChannelData *megagroup) {
|
||||
auto &membersList = megagroup->mgInfo->lastParticipants;
|
||||
for (int i = 0, count = _list.size(); i < count; ++i) {
|
||||
if (_list.at(i)->user != membersList.at(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_list.reserve(membersList.size());
|
||||
for (int i = _list.size(), count = membersList.size(); i < count; ++i) {
|
||||
addUser(megagroup, membersList.at(i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MembersWidget::setMemberFlags(Member *member, ChannelData *megagroup) {
|
||||
if (member->user->isSelf()) {
|
||||
member->canBeKicked = false;
|
||||
} else if (megagroup->amCreator() || (megagroup->amEditor() && !member->isAdmin)) {
|
||||
member->canBeKicked = true;
|
||||
} else {
|
||||
member->canBeKicked = false;
|
||||
}
|
||||
member->isAdmin = megagroup->mgInfo->lastAdmins.contains(member->user);
|
||||
}
|
||||
|
||||
MembersWidget::Member *MembersWidget::getMember(UserData *user) {
|
||||
auto it = _membersByUser.constFind(user);
|
||||
if (it == _membersByUser.cend()) {
|
||||
auto member = new Member(user);
|
||||
it = _membersByUser.insert(user, member);
|
||||
member->online = !user->botInfo && App::onlineColorUse(user->onlineTill, _now);
|
||||
member->onlineTill = user->onlineTill;
|
||||
member->onlineForSort = App::onlineForSort(user, _now);
|
||||
}
|
||||
return it.value();
|
||||
}
|
||||
|
||||
void MembersWidget::paintMember(Painter &p, int x, int y, Member *member, bool selected, bool selectedKick) {
|
||||
if (selected) {
|
||||
paintOutlinedRect(p, x, y, width() - x, st::profileMemberHeight);
|
||||
}
|
||||
int skip = st::profileMemberPhotoPosition.x();
|
||||
|
||||
member->user->paintUserpicLeft(p, st::profileMemberPhotoSize, x + st::profileMemberPhotoPosition.x(), y + st::profileMemberPhotoPosition.y(), width());
|
||||
|
||||
if (member->name.isEmpty()) {
|
||||
member->name.setText(st::semiboldFont, App::peerName(member->user), _textNameOptions);
|
||||
}
|
||||
int nameLeft = x + st::profileMemberNamePosition.x();
|
||||
int nameTop = y + st::profileMemberNamePosition.y();
|
||||
int nameWidth = width() - nameLeft - skip;
|
||||
if (member->canBeKicked && selected) {
|
||||
p.setFont(selectedKick ? st::normalFont->underline() : st::normalFont);
|
||||
p.setPen(st::windowActiveTextFg);
|
||||
p.drawTextLeft(nameLeft + nameWidth - _removeWidth, nameTop, width(), lang(lng_profile_kick), _removeWidth);
|
||||
nameWidth -= _removeWidth + skip;
|
||||
}
|
||||
if (member->isAdmin) {
|
||||
nameWidth -= st::profileMemberAdminIcon.width();
|
||||
int iconLeft = nameLeft + qMin(nameWidth, member->name.maxWidth());
|
||||
st::profileMemberAdminIcon.paint(p, QPoint(iconLeft, nameTop), width());
|
||||
}
|
||||
p.setPen(st::profileMemberNameFg);
|
||||
member->name.drawLeftElided(p, nameLeft, nameTop, nameWidth, width());
|
||||
|
||||
if (member->onlineText.isEmpty() || (member->onlineTextTill <= _now)) {
|
||||
if (member->user->botInfo) {
|
||||
bool seesAllMessages = (member->user->botInfo->readsAllHistory || member->isAdmin);
|
||||
member->onlineText = lang(seesAllMessages ? lng_status_bot_reads_all : lng_status_bot_not_reads_all);
|
||||
member->onlineTextTill = _now + 86400;
|
||||
} else {
|
||||
member->online = App::onlineColorUse(member->onlineTill, _now);
|
||||
member->onlineText = App::onlineText(member->onlineTill, _now);
|
||||
member->onlineTextTill = _now + App::onlineWillChangeIn(member->onlineTill, _now);
|
||||
}
|
||||
}
|
||||
if (_updateOnlineAt <= _now || _updateOnlineAt > member->onlineTextTill) {
|
||||
_updateOnlineAt = member->onlineTextTill;
|
||||
_updateOnlineTimer.start((_updateOnlineAt - _now + 1) * 1000);
|
||||
}
|
||||
|
||||
if (member->online) {
|
||||
p.setPen(st::profileMemberStatusFgActive);
|
||||
} else {
|
||||
p.setPen(selected ? st::profileMemberStatusFgOver : st::profileMemberStatusFg);
|
||||
}
|
||||
p.setFont(st::normalFont);
|
||||
p.drawTextLeft(x + st::profileMemberStatusPosition.x(), y + st::profileMemberStatusPosition.y(), width(), member->onlineText);
|
||||
}
|
||||
|
||||
void MembersWidget::onKickConfirm() {
|
||||
|
||||
}
|
||||
|
||||
void MembersWidget::onUpdateOnlineDisplay() {
|
||||
if (_sortByOnline) {
|
||||
_now = unixtime();
|
||||
|
||||
bool changed = false;
|
||||
for_const (auto member, _list) {
|
||||
if (!member->online) {
|
||||
if (!member->user->isSelf()) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool isOnline = !member->user->botInfo && App::onlineColorUse(member->onlineTill, _now);
|
||||
if (!isOnline) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
updateOnlineCount();
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
MembersWidget::~MembersWidget() {
|
||||
auto members = createAndSwap(_membersByUser);
|
||||
for_const (auto member, members) {
|
||||
delete member;
|
||||
}
|
||||
}
|
||||
|
||||
ChannelMembersWidget::ChannelMembersWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_participants_section)) {
|
||||
auto observeEvents = UpdateFlag::ChannelCanViewAdmins
|
||||
| UpdateFlag::ChannelCanViewMembers
|
||||
|
|
|
@ -22,6 +22,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include "profile/profile_block_widget.h"
|
||||
|
||||
class FlatLabel;
|
||||
|
||||
namespace Ui {
|
||||
class LeftOutlineButton;
|
||||
} // namespace Ui
|
||||
|
@ -33,13 +35,112 @@ struct PeerUpdate;
|
|||
namespace Profile {
|
||||
|
||||
class MembersWidget : public BlockWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MembersWidget(QWidget *parent, PeerData *peer);
|
||||
|
||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
int onlineCount() const {
|
||||
return _onlineCount;
|
||||
}
|
||||
|
||||
~MembersWidget();
|
||||
|
||||
protected:
|
||||
// Resizes content and counts natural widget height for the desired width.
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
void paintContents(Painter &p) override;
|
||||
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void enterEvent(QEvent *e) override;
|
||||
void enterFromChildEvent(QEvent *e) override {
|
||||
enterEvent(e);
|
||||
}
|
||||
void leaveEvent(QEvent *e) override;
|
||||
void leaveToChildEvent(QEvent *e) override {
|
||||
leaveEvent(e);
|
||||
}
|
||||
|
||||
signals:
|
||||
void onlineCountUpdated(int onlineCount);
|
||||
|
||||
private slots:
|
||||
void onKickConfirm();
|
||||
void onUpdateOnlineDisplay();
|
||||
|
||||
private:
|
||||
// Observed notifications.
|
||||
void notifyPeerUpdated(const Notify::PeerUpdate &update);
|
||||
void repaintCallback();
|
||||
|
||||
void preloadUserPhotos();
|
||||
|
||||
void refreshMembers();
|
||||
void fillChatMembers(ChatData *chat);
|
||||
void fillMegagroupMembers(ChannelData *megagroup);
|
||||
void sortMembers();
|
||||
void updateOnlineCount();
|
||||
void checkSelfAdmin(ChatData *chat);
|
||||
void checkSelfAdmin(ChannelData *megagroup);
|
||||
|
||||
void refreshVisibility();
|
||||
void updateSelection();
|
||||
void setSelected(int selected, bool selectedKick);
|
||||
void repaintSelectedRow();
|
||||
void refreshUserOnline(UserData *user);
|
||||
|
||||
int getListLeft() const;
|
||||
int getListTop() const;
|
||||
|
||||
struct Member {
|
||||
Member(UserData *user) : user(user) {
|
||||
}
|
||||
UserData *user;
|
||||
Text name;
|
||||
QString onlineText;
|
||||
TimeId onlineTextTill = 0;
|
||||
TimeId onlineTill = 0;
|
||||
TimeId onlineForSort = 0;
|
||||
bool online = false;
|
||||
bool isAdmin = false;
|
||||
bool canBeKicked = false;
|
||||
};
|
||||
Member *getMember(UserData *user);
|
||||
void paintMember(Painter &p, int x, int y, Member *member, bool selected, bool selectedKick);
|
||||
void paintOutlinedRect(Painter &p, int x, int y, int w, int h) const;
|
||||
void setMemberFlags(Member *member, ChatData *chat);
|
||||
Member *addUser(ChatData *chat, UserData *user);
|
||||
void setMemberFlags(Member *member, ChannelData *megagroup);
|
||||
Member *addUser(ChannelData *megagroup, UserData *user);
|
||||
bool addUsersToEnd(ChannelData *megagroup);
|
||||
|
||||
ChildWidget<FlatLabel> _limitReachedInfo = { nullptr };
|
||||
|
||||
QList<Member*> _list;
|
||||
QMap<UserData*, Member*> _membersByUser;
|
||||
bool _sortByOnline = false;
|
||||
TimeId _now = 0;
|
||||
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
|
||||
int _selected = -1;
|
||||
int _pressed = -1;
|
||||
bool _selectedKick = false;
|
||||
bool _pressedKick = false;
|
||||
UserData *_kicking = nullptr;
|
||||
QPoint _mousePosition;
|
||||
|
||||
int _onlineCount = 0;
|
||||
TimeId _updateOnlineAt = 0;
|
||||
QTimer _updateOnlineTimer;
|
||||
|
||||
int _removeWidth = 0;
|
||||
|
||||
};
|
||||
|
||||
class ChannelMembersWidget : public BlockWidget {
|
||||
|
|
|
@ -46,7 +46,6 @@ Widget::Widget(QWidget *parent, PeerData *peer) : Window::SectionWidget(parent)
|
|||
_scroll->move(0, _fixedBar->height());
|
||||
_scroll->show();
|
||||
|
||||
connect(_scroll, SIGNAL(scrolled()), _inner, SLOT(updateSelected()));
|
||||
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(_inner, SIGNAL(cancelled()), _fixedBar, SLOT(onBack()));
|
||||
}
|
||||
|
|
|
@ -380,9 +380,11 @@ void UserData::madeAction() {
|
|||
if (onlineTill <= 0 && -onlineTill < t) {
|
||||
onlineTill = -t - SetOnlineAfterActivity;
|
||||
App::markPeerUpdated(this);
|
||||
Notify::peerUpdatedDelayed(this, Notify::PeerUpdate::Flag::UserOnlineChanged);
|
||||
} else if (onlineTill > 0 && onlineTill < t + 1) {
|
||||
onlineTill = t + SetOnlineAfterActivity;
|
||||
App::markPeerUpdated(this);
|
||||
Notify::peerUpdatedDelayed(this, Notify::PeerUpdate::Flag::UserOnlineChanged);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -270,6 +270,8 @@ public:
|
|||
const ChatData *asChat() const;
|
||||
ChannelData *asChannel();
|
||||
const ChannelData *asChannel() const;
|
||||
ChannelData *asMegagroup();
|
||||
const ChannelData *asMegagroup() const;
|
||||
|
||||
ChatData *migrateFrom() const;
|
||||
ChannelData *migrateTo() const;
|
||||
|
@ -882,6 +884,18 @@ inline const ChannelData *PeerData::asChannel() const {
|
|||
inline const ChannelData *asChannel(const PeerData *peer) {
|
||||
return peer ? peer->asChannel() : nullptr;
|
||||
}
|
||||
inline ChannelData *PeerData::asMegagroup() {
|
||||
return isMegagroup() ? static_cast<ChannelData*>(this) : nullptr;
|
||||
}
|
||||
inline ChannelData *asMegagroup(PeerData *peer) {
|
||||
return peer ? peer->asMegagroup() : nullptr;
|
||||
}
|
||||
inline const ChannelData *PeerData::asMegagroup() const {
|
||||
return isMegagroup() ? static_cast<const ChannelData*>(this) : nullptr;
|
||||
}
|
||||
inline const ChannelData *asMegagroup(const PeerData *peer) {
|
||||
return peer ? peer->asMegagroup() : nullptr;
|
||||
}
|
||||
inline bool isMegagroup(const PeerData *peer) {
|
||||
return peer ? peer->isMegagroup() : false;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue