Members block almost done in the new profile implementation.

Member kicking, upgrade to supergroup and testing is left.
This commit is contained in:
John Preston 2016-06-03 10:20:24 +03:00
parent 91d516f18c
commit ea8f01bd74
19 changed files with 779 additions and 116 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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()) {

View File

@ -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);
}
}
}

View File

@ -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) {

View File

@ -51,6 +51,7 @@ struct PeerUpdate {
UserPhoneChanged = 0x00040000U,
UserIsBlocked = 0x00080000U,
BotCommandsChanged = 0x00100000U,
UserOnlineChanged = 0x00200000U,
ChatCanEdit = 0x00010000U,

View File

@ -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) },
};

View File

@ -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;

View File

@ -37,6 +37,9 @@ public:
virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) {
}
virtual ~BlockWidget() {
}
signals:
void heightUpdated();

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);

View File

@ -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

View File

@ -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 {

View File

@ -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()));
}

View File

@ -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);
}
}

View File

@ -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;
}