Refactor NotifySettings in PeerData.

This commit is contained in:
John Preston 2017-12-04 21:46:03 +04:00
parent 116e3fd9c5
commit 62568daffe
21 changed files with 562 additions and 290 deletions

View File

@ -975,6 +975,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_unblock_button" = "Unblock";
"lng_channel_mute" = "Mute";
"lng_channel_unmute" = "Unmute";
"lng_saved_messages" = "Saved messages";
"lng_dialogs_text_with_from" = "{from_part} {message}";
"lng_dialogs_text_from_wrapped" = "{from}:";

View File

@ -1432,23 +1432,36 @@ void ApiWrap::checkQuitPreventFinished() {
}
}
PeerData *ApiWrap::notifySettingReceived(MTPInputNotifyPeer notifyPeer, const MTPPeerNotifySettings &settings) {
PeerData *ApiWrap::notifySettingReceived(
MTPInputNotifyPeer notifyPeer,
const MTPPeerNotifySettings &settings) {
PeerData *requestedPeer = nullptr;
switch (notifyPeer.type()) {
case mtpc_inputNotifyAll: App::main()->applyNotifySetting(MTP_notifyAll(), settings); break;
case mtpc_inputNotifyUsers: App::main()->applyNotifySetting(MTP_notifyUsers(), settings); break;
case mtpc_inputNotifyChats: App::main()->applyNotifySetting(MTP_notifyChats(), settings); break;
case mtpc_inputNotifyAll:
App::main()->applyNotifySetting(MTP_notifyAll(), settings);
break;
case mtpc_inputNotifyUsers:
App::main()->applyNotifySetting(MTP_notifyUsers(), settings);
break;
case mtpc_inputNotifyChats:
App::main()->applyNotifySetting(MTP_notifyChats(), settings);
break;
case mtpc_inputNotifyPeer: {
auto &peer = notifyPeer.c_inputNotifyPeer().vpeer;
switch (peer.type()) {
case mtpc_inputPeerEmpty: App::main()->applyNotifySetting(MTP_notifyPeer(MTP_peerUser(MTP_int(0))), settings); break;
case mtpc_inputPeerEmpty: App::main()->applyNotifySetting(
MTP_notifyPeer(MTP_peerUser(MTP_int(0))),
settings);
break;
case mtpc_inputPeerSelf: requestedPeer = App::self(); break;
case mtpc_inputPeerUser: requestedPeer = App::user(peerFromUser(peer.c_inputPeerUser().vuser_id)); break;
case mtpc_inputPeerChat: requestedPeer = App::chat(peerFromChat(peer.c_inputPeerChat().vchat_id)); break;
case mtpc_inputPeerChannel: requestedPeer = App::channel(peerFromChannel(peer.c_inputPeerChannel().vchannel_id)); break;
}
if (requestedPeer) {
App::main()->applyNotifySetting(MTP_notifyPeer(peerToMTP(requestedPeer->id)), settings);
App::main()->applyNotifySetting(
MTP_notifyPeer(peerToMTP(requestedPeer->id)),
settings);
}
} break;
}

View File

@ -60,7 +60,7 @@ namespace {
using PeersData = QHash<PeerId, PeerData*>;
PeersData peersData;
using MutedPeers = QMap<PeerData*, bool>;
using MutedPeers = QMap<not_null<PeerData*>, bool>;
MutedPeers mutedPeers;
PhotosData photosData;
@ -195,9 +195,6 @@ namespace {
Window::Theme::Background()->reset();
cSetOtherOnline(0);
globalNotifyAllPtr = UnknownNotifySettings;
globalNotifyUsersPtr = UnknownNotifySettings;
globalNotifyChatsPtr = UnknownNotifySettings;
clearStorageImages();
if (auto w = wnd()) {
w->updateConnectingStatus();
@ -2598,28 +2595,32 @@ namespace {
return QString();
}
void regMuted(PeerData *peer, int32 changeIn) {
void regMuted(not_null<PeerData*> peer, TimeMs changeIn) {
::mutedPeers.insert(peer, true);
if (App::main()) App::main()->updateMutedIn(changeIn);
App::main()->updateMutedIn(changeIn);
}
void unregMuted(PeerData *peer) {
void unregMuted(not_null<PeerData*> peer) {
::mutedPeers.remove(peer);
}
void updateMuted() {
int32 changeInMin = 0;
for (MutedPeers::iterator i = ::mutedPeers.begin(); i != ::mutedPeers.end();) {
int32 changeIn = 0;
History *h = App::history(i.key()->id);
if (isNotifyMuted(i.key()->notify, &changeIn)) {
h->setMute(true);
if (changeIn && (!changeInMin || changeIn < changeInMin)) {
changeInMin = changeIn;
auto changeInMin = TimeMs(0);
for (auto i = ::mutedPeers.begin(); i != ::mutedPeers.end();) {
const auto history = App::historyLoaded(i.key()->id);
const auto muteFinishesIn = i.key()->notifyMuteFinishesIn();
if (muteFinishesIn > 0) {
if (history) {
history->changeMute(true);
}
if (!changeInMin || muteFinishesIn < changeInMin) {
changeInMin = muteFinishesIn;
}
++i;
} else {
h->setMute(false);
if (history) {
history->changeMute(false);
}
i = ::mutedPeers.erase(i);
}
}

View File

@ -262,8 +262,8 @@ namespace App {
void stopRoundVideoPlayback();
void stopGifItems();
void regMuted(PeerData *peer, int32 changeIn);
void unregMuted(PeerData *peer);
void regMuted(not_null<PeerData*> peer, TimeMs changeIn);
void unregMuted(not_null<PeerData*> peer);
void updateMuted();
void setProxySettings(QNetworkAccessManager &manager);

View File

@ -14,16 +14,22 @@
#include "ui/widgets/checkbox.h"
#include "ui/widgets/labels.h"
namespace {
constexpr auto kForeverHours = 24 * 365;
} // namespace
void MuteSettingsBox::prepare() {
setTitle(langFactory(lng_disable_notifications_from_tray));
int y = 0;
auto y = 0;
object_ptr<Ui::FlatLabel> info(this, st::boxLabel);
info->setText(lang(lng_mute_box_tip));
info->moveToLeft(st::boxPadding.left(), y);
y += info->height() + st::boxLittleSkip;
auto icon = object_ptr<Ui::UserpicButton>(
const auto icon = object_ptr<Ui::UserpicButton>(
this,
controller(),
_peer,
@ -40,27 +46,34 @@ void MuteSettingsBox::prepare() {
// the icon is always higher than this chat title
y += icon->height() + st::boxMediumSkip;
const int FOREVER = 8760; // in fact, this is mute only for 1 year
auto group = std::make_shared<Ui::RadiobuttonGroup>(FOREVER);
// in fact, this is mute only for 1 year
const auto group = std::make_shared<Ui::RadiobuttonGroup>(kForeverHours);
y += st::boxOptionListPadding.top();
for (int value : { 1, 4, 18, 72, FOREVER }) { // periods in hours
QString text;
if (value < 24) {
text = lng_mute_duration_hours(lt_count, value);
} else if (value < FOREVER) {
text = lng_rights_chat_banned_day(lt_count, value / 24);
} else {
text = lang(lng_rights_chat_banned_forever);
}
object_ptr<Ui::Radiobutton> option(this, group, value, text);
for (const auto hours : { 1, 4, 18, 72, kForeverHours }) {
const auto text = [&] {
if (hours < 24) {
return lng_mute_duration_hours(lt_count, hours);
} else if (hours < kForeverHours) {
return lng_rights_chat_banned_day(lt_count, hours / 24);
} else {
return lang(lng_rights_chat_banned_forever);
}
}();
object_ptr<Ui::Radiobutton> option(this, group, hours, text);
option->moveToLeft(st::boxPadding.left(), y);
y += option->heightNoMargins() + st::boxOptionListSkip;
}
y += st::boxOptionListPadding.bottom() - st::boxOptionListSkip + st::defaultCheckbox.margin.bottom();
y += st::boxOptionListPadding.bottom()
- st::boxOptionListSkip
+ st::defaultCheckbox.margin.bottom();
addButton(langFactory(lng_box_ok), [this, group] {
App::main()->updateNotifySetting(_peer, NotifySettingSetMuted,
SilentNotifiesDontChange, group->value() * 3600);
auto muteForSeconds = group->value() * 3600;
App::main()->updateNotifySettings(
_peer,
Data::NotifySettings::MuteChange::Mute,
Data::NotifySettings::SilentPostsChange::Ignore,
muteForSeconds);
closeBox();
});
addButton(langFactory(lng_cancel), [this] { closeBox(); });

View File

@ -0,0 +1,217 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#include "data/data_notify_settings.h"
namespace Data {
namespace {
MTPinputPeerNotifySettings DefaultSettings() {
const auto flags = MTPDpeerNotifySettings::Flag::f_show_previews;
const auto muteValue = TimeId(0);
return MTP_inputPeerNotifySettings(
MTP_flags(mtpCastFlags(flags)),
MTP_int(muteValue),
MTP_string("default"));
}
} // namespace
class NotifySettingsValue {
public:
NotifySettingsValue(const MTPDpeerNotifySettings &data);
using MuteChange = NotifySettings::MuteChange;
using SilentPostsChange = NotifySettings::SilentPostsChange;
bool change(const MTPDpeerNotifySettings &data);
bool change(
MuteChange mute,
SilentPostsChange silent,
int muteForSeconds);
TimeMs muteFinishesIn() const;
bool silentPosts() const;
MTPinputPeerNotifySettings serialize() const;
private:
bool change(
MTPDpeerNotifySettings::Flags flags,
TimeId mute,
QString sound);
MTPDpeerNotifySettings::Flags _flags;
TimeId _mute;
QString _sound;
};
NotifySettingsValue::NotifySettingsValue(const MTPDpeerNotifySettings &data)
: _flags(data.vflags.v)
, _mute(data.vmute_until.v)
, _sound(qs(data.vsound)) {
}
bool NotifySettingsValue::silentPosts() const {
return _flags & MTPDpeerNotifySettings::Flag::f_silent;
}
bool NotifySettingsValue::change(const MTPDpeerNotifySettings &data) {
return change(data.vflags.v, data.vmute_until.v, qs(data.vsound));
}
bool NotifySettingsValue::change(
MuteChange mute,
SilentPostsChange silent,
int muteForSeconds) {
const auto newFlags = [&] {
auto result = _flags;
if (silent == SilentPostsChange::Silent) {
result |= MTPDpeerNotifySettings::Flag::f_silent;
} else if (silent == SilentPostsChange::Notify) {
result &= ~MTPDpeerNotifySettings::Flag::f_silent;
}
return result;
}();
const auto newMute = (mute == MuteChange::Mute)
? (unixtime() + muteForSeconds)
: (mute == MuteChange::Ignore) ? _mute : 0;
const auto newSound = (newMute == 0 && _sound.isEmpty())
? qsl("default")
: _sound;
return change(newFlags, newMute, newSound);
}
bool NotifySettingsValue::change(
MTPDpeerNotifySettings::Flags flags,
TimeId mute,
QString sound) {
if (_flags == flags && _mute == mute && _sound == sound) {
return false;
}
_flags = flags;
_mute = mute;
_sound = sound;
return true;
}
TimeMs NotifySettingsValue::muteFinishesIn() const {
auto now = unixtime();
if (_mute > now) {
return (_mute - now + 1) * 1000LL;
}
return 0;
}
MTPinputPeerNotifySettings NotifySettingsValue::serialize() const {
return MTP_inputPeerNotifySettings(
MTP_flags(mtpCastFlags(_flags)),
MTP_int(_mute),
MTP_string(_sound));
}
bool NotifySettings::change(const MTPPeerNotifySettings &settings) {
switch (settings.type()) {
case mtpc_peerNotifySettingsEmpty: {
if (!_known || _value) {
_known = true;
_value = nullptr;
return true;
}
return false;
} break;
case mtpc_peerNotifySettings: {
auto &data = settings.c_peerNotifySettings();
if (_value) {
return _value->change(data);
}
_known = true;
_value = std::make_unique<NotifySettingsValue>(data);
return true;
} break;
}
Unexpected("Type in NotifySettings::change()");
}
NotifySettings::NotifySettings() = default;
bool NotifySettings::change(
MuteChange mute,
SilentPostsChange silent,
int muteForSeconds) {
Expects(mute != MuteChange::Mute || muteForSeconds > 0);
if (mute == MuteChange::Ignore && silent == SilentPostsChange::Ignore) {
return false;
}
if (_value) {
return _value->change(mute, silent, muteForSeconds);
}
const auto asEmpty = [&] {
if (mute == MuteChange::Mute) {
return false;
}
if (silent == SilentPostsChange::Silent) {
return false;
}
return true;
}();
if (asEmpty) {
return change(MTP_peerNotifySettingsEmpty());
}
const auto flags = MTPDpeerNotifySettings::Flag::f_show_previews
| ((silent == SilentPostsChange::Silent)
? MTPDpeerNotifySettings::Flag::f_silent
: MTPDpeerNotifySettings::Flag(0));
const auto muteUntil = (mute == MuteChange::Mute)
? (unixtime() + muteForSeconds)
: 0;
return change(MTP_peerNotifySettings(
MTP_flags(flags),
MTP_int(muteUntil),
MTP_string("default")));
}
TimeMs NotifySettings::muteFinishesIn() const {
return _value
? _value->muteFinishesIn()
: 0LL;
}
bool NotifySettings::settingsUnknown() const {
return !_known;
}
bool NotifySettings::silentPosts() const {
return _value
? _value->silentPosts()
: false;
}
MTPinputPeerNotifySettings NotifySettings::serialize() const {
return _value
? _value->serialize()
: DefaultSettings();
}
NotifySettings::~NotifySettings() = default;
} // namespace Data

View File

@ -0,0 +1,60 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
namespace Data {
class NotifySettingsValue;
class NotifySettings {
public:
NotifySettings();
enum class MuteChange {
Ignore,
Mute,
Unmute,
};
enum class SilentPostsChange {
Ignore,
Silent,
Notify,
};
bool change(const MTPPeerNotifySettings &settings);
bool change(
MuteChange mute,
SilentPostsChange silent,
int muteForSeconds);
TimeMs muteFinishesIn() const;
bool settingsUnknown() const;
bool silentPosts() const;
MTPinputPeerNotifySettings serialize() const;
~NotifySettings();
private:
bool _known = false;
std::unique_ptr<NotifySettingsValue> _value;
};
} // namespace Data

View File

@ -259,9 +259,6 @@ EmptyUserpic::~EmptyUserpic() = default;
using UpdateFlag = Notify::PeerUpdate::Flag;
NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats;
NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersPtr = UnknownNotifySettings, globalNotifyChatsPtr = UnknownNotifySettings;
PeerClickHandler::PeerClickHandler(not_null<PeerData*> peer)
: _peer(peer) {
}
@ -291,6 +288,8 @@ PeerData::PeerData(const PeerId &id)
_userpicEmpty.set(id, QString());
}
PeerData::~PeerData() = default;
void PeerData::updateNameDelayed(
const QString &newName,
const QString &newNameOrPhone,

View File

@ -22,50 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "data/data_types.h"
#include "data/data_flags.h"
struct NotifySettings {
NotifySettings() = default;
bool previews() const {
return flags & MTPDpeerNotifySettings::Flag::f_show_previews;
}
bool silent() const {
return flags & MTPDpeerNotifySettings::Flag::f_silent;
}
MTPDpeerNotifySettings::Flags flags
= MTPDpeerNotifySettings::Flag::f_show_previews;
TimeId mute = 0;
QString sound = qsl("default");
};
typedef NotifySettings *NotifySettingsPtr;
static const NotifySettingsPtr UnknownNotifySettings
= NotifySettingsPtr(0);
static const NotifySettingsPtr EmptyNotifySettings
= NotifySettingsPtr(1);
extern NotifySettings globalNotifyAll;
extern NotifySettings globalNotifyUsers;
extern NotifySettings globalNotifyChats;
extern NotifySettingsPtr globalNotifyAllPtr;
extern NotifySettingsPtr globalNotifyUsersPtr;
extern NotifySettingsPtr globalNotifyChatsPtr;
inline bool isNotifyMuted(
NotifySettingsPtr settings,
TimeId *changeIn = nullptr) {
if (settings != UnknownNotifySettings
&& settings != EmptyNotifySettings) {
auto t = unixtime();
if (settings->mute > t) {
if (changeIn) *changeIn = settings->mute - t + 1;
return true;
}
}
if (changeIn) *changeIn = 0;
return false;
}
#include "data/data_notify_settings.h"
int PeerColorIndex(PeerId peerId);
int PeerColorIndex(int32 bareId);
@ -142,12 +99,7 @@ protected:
PeerData &operator=(const PeerData &other) = delete;
public:
virtual ~PeerData() {
if (notify != UnknownNotifySettings
&& notify != EmptyNotifySettings) {
delete base::take(notify);
}
}
virtual ~PeerData();
bool isUser() const {
return peerIsUser(id);
@ -163,11 +115,32 @@ public:
}
bool isVerified() const;
bool isMegagroup() const;
bool isMuted() const {
return (notify != EmptyNotifySettings)
&& (notify != UnknownNotifySettings)
&& (notify->mute >= unixtime());
TimeMs notifyMuteFinishesIn() const {
return _notify.muteFinishesIn();
}
bool notifyChange(const MTPPeerNotifySettings &settings) {
return _notify.change(settings);
}
bool notifyChange(
Data::NotifySettings::MuteChange mute,
Data::NotifySettings::SilentPostsChange silent,
int muteForSeconds) {
return _notify.change(mute, silent, muteForSeconds);
}
bool notifySettingsUnknown() const {
return _notify.settingsUnknown();
}
bool notifySilentPosts() const {
return _notify.silentPosts();
}
MTPinputPeerNotifySettings notifySerialize() const {
return _notify.serialize();
}
bool isMuted() const {
return (notifyMuteFinishesIn() > 0);
}
bool canWrite() const;
UserData *asUser();
const UserData *asUser() const;
@ -265,8 +238,6 @@ public:
int nameVersion = 1;
NotifySettingsPtr notify = UnknownNotifySettings;
// if this string is not empty we must not allow to open the
// conversation and we must show this string instead
virtual QString restrictionReason() const {
@ -296,6 +267,8 @@ protected:
private:
void fillNames();
Data::NotifySettings _notify;
ClickHandlerPtr _openLink;
NameWords _nameWords; // for filtering
NameFirstChars _nameFirstChars;

View File

@ -1487,7 +1487,10 @@ void DialogsInner::dialogsReceived(const QVector<MTPDialog> &added) {
}
}
}
App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, history);
App::main()->applyNotifySetting(
MTP_notifyPeer(d.vpeer),
d.vnotify_settings,
history);
if (!history->isPinnedDialog() && !history->lastMsgDate.isNull()) {
addSavedPeersAfter(history->lastMsgDate);

View File

@ -85,7 +85,7 @@ History::History(const PeerId &peerId)
: peer(App::peer(peerId))
, lastItemTextCache(st::dialogsTextWidthMin)
, cloudDraftTextCache(st::dialogsTextWidthMin)
, _mute(isNotifyMuted(peer->notify))
, _mute(peer->isMuted())
, _sendActionText(st::dialogsTextWidthMin) {
if (peer->isUser() && peer->asUser()->botInfo) {
outboxReadBefore = INT_MAX;
@ -1912,21 +1912,23 @@ void History::setUnreadCount(int newUnreadCount) {
}
}
void History::setMute(bool newMute) {
if (_mute != newMute) {
_mute = newMute;
if (inChatList(Dialogs::Mode::All)) {
if (_unreadCount) {
App::histories().unreadMuteChanged(_unreadCount, newMute);
Notify::unreadCounterUpdated();
}
Notify::historyMuteUpdated(this);
}
updateChatListEntry();
Notify::peerUpdatedDelayed(
peer,
Notify::PeerUpdate::Flag::NotificationsEnabled);
bool History::changeMute(bool newMute) {
if (_mute == newMute) {
return false;
}
_mute = newMute;
if (inChatList(Dialogs::Mode::All)) {
if (_unreadCount) {
App::histories().unreadMuteChanged(_unreadCount, newMute);
Notify::unreadCounterUpdated();
}
Notify::historyMuteUpdated(this);
}
updateChatListEntry();
Notify::peerUpdatedDelayed(
peer,
Notify::PeerUpdate::Flag::NotificationsEnabled);
return true;
}
void History::getNextShowFrom(HistoryBlock *block, int i) {

View File

@ -261,7 +261,7 @@ public:
bool mute() const {
return _mute;
}
void setMute(bool newMute);
bool changeMute(bool newMute);
void getNextShowFrom(HistoryBlock *block, int i);
void addUnreadBar();
void destroyUnreadBar();

View File

@ -501,9 +501,16 @@ void SilentToggle::mouseReleaseEvent(QMouseEvent *e) {
setChecked(!_checked);
IconButton::mouseReleaseEvent(e);
Ui::Tooltip::Show(0, this);
auto p = App::main() ? App::main()->peer() : nullptr;
if (p && p->isChannel() && p->notify != UnknownNotifySettings) {
App::main()->updateNotifySetting(p, NotifySettingDontChange, _checked ? SilentNotifiesSetSilent : SilentNotifiesSetNotify);
if (const auto peer = App::main() ? App::main()->peer() : nullptr) {
if (peer->isChannel() && !peer->notifySettingsUnknown()) {
const auto silentState = _checked
? Data::NotifySettings::SilentPostsChange::Silent
: Data::NotifySettings::SilentPostsChange::Notify;
App::main()->updateNotifySettings(
peer,
Data::NotifySettings::MuteChange::Ignore,
silentState);
}
}
}
@ -695,6 +702,7 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null<Window::Controller*> cont
| UpdateFlag::AdminsChanged
| UpdateFlag::MembersChanged
| UpdateFlag::UserOnlineChanged
| UpdateFlag::NotificationsEnabled
| UpdateFlag::ChannelAmIn;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(changes, [this](const Notify::PeerUpdate &update) {
if (update.peer == _peer) {
@ -711,6 +719,9 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null<Window::Controller*> cont
return;
}
}
if (update.flags & UpdateFlag::NotificationsEnabled) {
updateNotifySettings();
}
if (update.flags & UpdateFlag::RestrictionReasonChanged) {
auto restriction = _peer->restrictionReason();
if (!restriction.isEmpty()) {
@ -1780,7 +1791,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
if (_channel) {
updateNotifySettings();
if (_peer->notify == UnknownNotifySettings) {
if (_peer->notifySettingsUnknown()) {
Auth().api().requestNotifySetting(_peer);
}
}
@ -1884,9 +1895,11 @@ void HistoryWidget::updateFieldSubmitSettings() {
void HistoryWidget::updateNotifySettings() {
if (!_peer || !_peer->isChannel()) return;
_muteUnmute->setText(lang(_history->mute() ? lng_channel_unmute : lng_channel_mute).toUpper());
if (_peer->notify != UnknownNotifySettings) {
_silent->setChecked(_peer->notify != EmptyNotifySettings && (_peer->notify->flags & MTPDpeerNotifySettings::Flag::f_silent));
_muteUnmute->setText(lang(_history->mute()
? lng_channel_unmute
: lng_channel_mute).toUpper());
if (!_peer->notifySettingsUnknown()) {
_silent->setChecked(_peer->notifySilentPosts());
if (_silent->isHidden() && hasSilentToggle()) {
updateControlsVisibility();
}
@ -3025,7 +3038,10 @@ bool HistoryWidget::joinFail(const RPCError &error, mtpRequestId req) {
}
void HistoryWidget::onMuteUnmute() {
App::main()->updateNotifySetting(_peer, _history->mute() ? NotifySettingSetNotify : NotifySettingSetMuted);
const auto muteState = _history->mute()
? Data::NotifySettings::MuteChange::Unmute
: Data::NotifySettings::MuteChange::Mute;
App::main()->updateNotifySettings(_peer, muteState);
}
void HistoryWidget::onBroadcastSilentChange() {
@ -3638,7 +3654,11 @@ bool HistoryWidget::readyToForward() const {
}
bool HistoryWidget::hasSilentToggle() const {
return _peer && _peer->isChannel() && !_peer->isMegagroup() && _peer->asChannel()->canPublish() && _peer->notify != UnknownNotifySettings;
return _peer
&& _peer->isChannel()
&& !_peer->isMegagroup()
&& _peer->asChannel()->canPublish()
&& !_peer->notifySettingsUnknown();
}
void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result) {

View File

@ -357,7 +357,7 @@ void WrapWidget::addProfileMenuButton() {
void WrapWidget::addProfileNotificationsButton() {
Expects(_topBar != nullptr);
auto peer = _controller->peer();
const auto peer = _controller->peer();
auto notifications = _topBar->addButton(
base::make_unique_q<Ui::IconButton>(
_topBar,
@ -365,18 +365,17 @@ void WrapWidget::addProfileNotificationsButton() {
? st::infoLayerTopBarNotifications
: st::infoTopBarNotifications)));
notifications->addClickHandler([peer] {
App::main()->updateNotifySetting(
peer,
peer->isMuted()
? NotifySettingSetNotify
: NotifySettingSetMuted);
const auto muteState = peer->isMuted()
? Data::NotifySettings::MuteChange::Unmute
: Data::NotifySettings::MuteChange::Mute;
App::main()->updateNotifySettings(peer, muteState);
});
Profile::NotificationsEnabledValue(peer)
| rpl::start_with_next([notifications](bool enabled) {
auto iconOverride = enabled
const auto iconOverride = enabled
? &st::infoNotificationsActive
: nullptr;
auto rippleOverride = enabled
const auto rippleOverride = enabled
? &st::lightButtonBgOver
: nullptr;
notifications->setIconOverride(iconOverride, iconOverride);

View File

@ -278,7 +278,7 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
}
object_ptr<Ui::RpWidget> DetailsFiller::setupMuteToggle() {
auto peer = _peer;
const auto peer = _peer;
auto result = object_ptr<Button>(
_wrap,
Lang::Viewer(lng_profile_enable_notifications),
@ -286,11 +286,10 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupMuteToggle() {
result->toggleOn(
NotificationsEnabledValue(peer)
)->addClickHandler([=] {
App::main()->updateNotifySetting(
peer,
peer->isMuted()
? NotifySettingSetNotify
: NotifySettingSetMuted);
const auto muteState = peer->isMuted()
? Data::NotifySettings::MuteChange::Unmute
: Data::NotifySettings::MuteChange::Mute;
App::main()->updateNotifySettings(peer, muteState);
});
object_ptr<FloatingIcon>(
result,

View File

@ -127,7 +127,8 @@ rpl::producer<bool> NotificationsEnabledValue(
return Notify::PeerUpdateValue(
peer,
Notify::PeerUpdate::Flag::NotificationsEnabled)
| rpl::map([peer] { return !peer->isMuted(); });
| rpl::map([peer] { return !peer->isMuted(); })
| rpl::distinct_until_changed();
}
rpl::producer<bool> IsContactValue(

View File

@ -820,11 +820,12 @@ void MainWidget::webPagesOrGamesUpdate() {
}
}
void MainWidget::updateMutedIn(int32 seconds) {
if (seconds > 86400) seconds = 86400;
int32 ms = seconds * 1000;
if (_updateMutedTimer.isActive() && _updateMutedTimer.remainingTime() <= ms) return;
_updateMutedTimer.start(ms);
void MainWidget::updateMutedIn(TimeMs delay) {
accumulate_max(delay, 24 * 3600 * 1000LL);
if (!_updateMutedTimer.isActive()
|| _updateMutedTimer.remainingTime() > delay) {
_updateMutedTimer.start(delay);
}
}
void MainWidget::onUpdateMuted() {
@ -3706,14 +3707,17 @@ void MainWidget::searchInPeer(PeerData *peer) {
void MainWidget::onUpdateNotifySettings() {
if (this != App::main()) return;
while (!updateNotifySettingPeers.isEmpty()) {
PeerData *peer = *updateNotifySettingPeers.begin();
updateNotifySettingPeers.erase(updateNotifySettingPeers.begin());
if (peer->notify == UnknownNotifySettings || peer->notify == EmptyNotifySettings) {
peer->notify = new NotifySettings();
}
MTP::send(MTPaccount_UpdateNotifySettings(MTP_inputNotifyPeer(peer->input), MTP_inputPeerNotifySettings(MTP_flags(mtpCastFlags(peer->notify->flags)), MTP_int(peer->notify->mute), MTP_string(peer->notify->sound))), RPCResponseHandler(), 0, updateNotifySettingPeers.isEmpty() ? 0 : 10);
while (!updateNotifySettingPeers.empty()) {
auto peer = *updateNotifySettingPeers.begin();
updateNotifySettingPeers.erase(updateNotifySettingPeers.begin());
MTP::send(
MTPaccount_UpdateNotifySettings(
MTP_inputNotifyPeer(peer->input),
peer->notifySerialize()),
RPCResponseHandler(),
0,
updateNotifySettingPeers.empty() ? 0 : 10);
}
}
@ -4450,112 +4454,60 @@ void MainWidget::startWithSelf(const MTPUserFull &result) {
}
}
void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *h) {
PeerData *updatePeer = nullptr;
bool changed = false;
switch (settings.type()) {
case mtpc_peerNotifySettingsEmpty:
switch (peer.type()) {
case mtpc_notifyAll: globalNotifyAllPtr = EmptyNotifySettings; break;
case mtpc_notifyUsers: globalNotifyUsersPtr = EmptyNotifySettings; break;
case mtpc_notifyChats: globalNotifyChatsPtr = EmptyNotifySettings; break;
case mtpc_notifyPeer: {
if ((updatePeer = App::peerLoaded(peerFromMTP(peer.c_notifyPeer().vpeer)))) {
changed = (updatePeer->notify != EmptyNotifySettings);
if (changed) {
if (updatePeer->notify != UnknownNotifySettings) {
delete updatePeer->notify;
}
updatePeer->notify = EmptyNotifySettings;
App::unregMuted(updatePeer);
if (!h) h = App::history(updatePeer->id);
h->setMute(false);
}
}
} break;
}
break;
case mtpc_peerNotifySettings: {
const auto &d(settings.c_peerNotifySettings());
NotifySettingsPtr setTo = UnknownNotifySettings;
switch (peer.type()) {
case mtpc_notifyAll: setTo = globalNotifyAllPtr = &globalNotifyAll; break;
case mtpc_notifyUsers: setTo = globalNotifyUsersPtr = &globalNotifyUsers; break;
case mtpc_notifyChats: setTo = globalNotifyChatsPtr = &globalNotifyChats; break;
case mtpc_notifyPeer: {
if ((updatePeer = App::peerLoaded(peerFromMTP(peer.c_notifyPeer().vpeer)))) {
if (updatePeer->notify == UnknownNotifySettings || updatePeer->notify == EmptyNotifySettings) {
changed = true;
updatePeer->notify = new NotifySettings();
}
setTo = updatePeer->notify;
}
} break;
}
if (setTo == UnknownNotifySettings) break;
auto sound = qs(d.vsound);
changed = (setTo->flags != d.vflags.v) || (setTo->mute != d.vmute_until.v) || (setTo->sound != sound);
if (changed) {
setTo->flags = d.vflags.v;
setTo->mute = d.vmute_until.v;
setTo->sound = sound;
if (updatePeer) {
if (!h) h = App::history(updatePeer->id);
int32 changeIn = 0;
if (isNotifyMuted(setTo, &changeIn)) {
Auth().notifications().clearFromHistory(h);
h->setMute(true);
App::regMuted(updatePeer, changeIn);
} else {
h->setMute(false);
}
}
}
} break;
void MainWidget::applyNotifySetting(
const MTPNotifyPeer &notifyPeer,
const MTPPeerNotifySettings &settings,
History *history) {
if (notifyPeer.type() != mtpc_notifyPeer) {
// Ignore those for now, they were not ever used.
return;
}
if (updatePeer) {
if (_history->peer() == updatePeer) {
_history->updateNotifySettings();
}
const auto &data = notifyPeer.c_notifyPeer();
const auto peer = App::peerLoaded(peerFromMTP(data.vpeer));
if (!peer || !peer->notifyChange(settings)) {
return;
}
updateNotifySettingsLocal(peer, history);
}
void MainWidget::updateNotifySettings(
not_null<PeerData*> peer,
Data::NotifySettings::MuteChange mute,
Data::NotifySettings::SilentPostsChange silent,
int muteForSeconds) {
if (peer->notifyChange(mute, silent, muteForSeconds)) {
updateNotifySettingsLocal(peer);
updateNotifySettingPeers.insert(peer);
updateNotifySettingTimer.start(NotifySettingSaveTimeout);
}
}
void MainWidget::updateNotifySetting(PeerData *peer, NotifySettingStatus notify, SilentNotifiesStatus silent, int muteFor) {
if (notify == NotifySettingDontChange && silent == SilentNotifiesDontChange) return;
void MainWidget::updateNotifySettingsLocal(
not_null<PeerData*> peer,
History *history) {
if (!history) {
history = App::historyLoaded(peer->id);
}
updateNotifySettingPeers.insert(peer);
if (peer->notify == EmptyNotifySettings) {
if (notify == NotifySettingSetMuted || silent == SilentNotifiesSetSilent) {
peer->notify = new NotifySettings();
}
} else if (peer->notify == UnknownNotifySettings) {
peer->notify = new NotifySettings();
const auto muteFinishesIn = peer->notifyMuteFinishesIn();
const auto muted = (muteFinishesIn > 0);
if (history && history->changeMute(muted)) {
// Notification already sent.
} else {
Notify::peerUpdatedDelayed(
peer,
Notify::PeerUpdate::Flag::NotificationsEnabled);
}
if (peer->notify != EmptyNotifySettings && peer->notify != UnknownNotifySettings) {
if (notify != NotifySettingDontChange) {
if ((notify != NotifySettingSetMuted) && peer->notify->sound.isEmpty()) {
peer->notify->sound = qsl("default");
}
peer->notify->mute = (notify == NotifySettingSetMuted) ? (unixtime() + muteFor) : 0;
}
if (silent == SilentNotifiesSetSilent) {
peer->notify->flags |= MTPDpeerNotifySettings::Flag::f_silent;
} else if (silent == SilentNotifiesSetNotify) {
peer->notify->flags &= ~MTPDpeerNotifySettings::Flag::f_silent;
if (muted) {
App::regMuted(peer, muteFinishesIn);
if (history) {
Auth().notifications().clearFromHistory(history);
}
} else {
App::unregMuted(peer);
}
if (notify != NotifySettingDontChange) {
if (notify == NotifySettingSetMuted) {
App::regMuted(peer, muteFor + 1);
} else {
App::unregMuted(peer);
}
App::history(peer->id)->setMute(notify == NotifySettingSetMuted);
}
if (_history->peer() == peer) _history->updateNotifySettings();
updateNotifySettingTimer.start(NotifySettingSaveTimeout);
}
void MainWidget::incrementSticker(DocumentData *sticker) {

View File

@ -75,17 +75,6 @@ class HistoryHider;
class StackItem;
enum SilentNotifiesStatus {
SilentNotifiesDontChange,
SilentNotifiesSetSilent,
SilentNotifiesSetNotify,
};
enum NotifySettingStatus {
NotifySettingDontChange,
NotifySettingSetMuted,
NotifySettingSetNotify,
};
namespace InlineBots {
namespace Layout {
class ItemBase;
@ -114,9 +103,17 @@ public:
void stickersBox(const MTPInputStickerSet &set);
bool started();
void applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *history = 0);
void applyNotifySetting(
const MTPNotifyPeer &notifyPeer,
const MTPPeerNotifySettings &settings,
History *history = 0);
void updateNotifySetting(PeerData *peer, NotifySettingStatus notify, SilentNotifiesStatus silent = SilentNotifiesDontChange, int muteFor = 86400 * 365);
void updateNotifySettings(
not_null<PeerData*> peer,
Data::NotifySettings::MuteChange mute,
Data::NotifySettings::SilentPostsChange silent
= Data::NotifySettings::SilentPostsChange::Ignore,
int muteForSeconds = 86400 * 365);
void incrementSticker(DocumentData *sticker);
@ -303,7 +300,7 @@ public:
void webPageUpdated(WebPageData *page);
void gameUpdated(GameData *game);
void updateMutedIn(int32 seconds);
void updateMutedIn(TimeMs delay);
void choosePeer(PeerId peerId, MsgId showAtMsgId); // does offerPeer or showPeerHistory
void clearBotStartToken(PeerData *peer);
@ -563,6 +560,10 @@ private:
void ensureFirstColumnResizeAreaCreated();
void ensureThirdColumnResizeAreaCreated();
void updateNotifySettingsLocal(
not_null<PeerData*> peer,
History *history = nullptr);
not_null<Window::Controller*> _controller;
bool _started = false;
@ -636,7 +637,7 @@ private:
TimeMs _lastSetOnline = 0;
bool _isIdle = false;
QSet<PeerData*> updateNotifySettingPeers;
base::flat_set<not_null<PeerData*>> updateNotifySettingPeers;
SingleTimer updateNotifySettingTimer;
typedef QMap<PeerData*, QPair<mtpRequestId, MsgId> > ReadRequests;

View File

@ -32,6 +32,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace Window {
namespace Notifications {
namespace {
// not more than one sound in 500ms from one peer - grouping
constexpr auto kMinimalAlertDelay = TimeMs(500);
} // namespace
System::System(AuthSession *session) : _authSession(session) {
createManager();
@ -69,13 +75,13 @@ void System::schedule(History *history, HistoryItem *item) {
return;
}
bool haveSetting = (history->peer->notify != UnknownNotifySettings);
auto haveSetting = !history->peer->notifySettingsUnknown();
if (haveSetting) {
if (history->peer->notify != EmptyNotifySettings && history->peer->notify->mute > unixtime()) {
if (history->peer->isMuted()) {
if (notifyByFrom) {
haveSetting = (item->from()->notify != UnknownNotifySettings);
haveSetting = !item->from()->notifySettingsUnknown();
if (haveSetting) {
if (notifyByFrom->notify != EmptyNotifySettings && notifyByFrom->notify->mute > unixtime()) {
if (notifyByFrom->isMuted()) {
history->popNotification(item);
return;
}
@ -88,7 +94,7 @@ void System::schedule(History *history, HistoryItem *item) {
}
}
} else {
if (notifyByFrom && notifyByFrom->notify == UnknownNotifySettings) {
if (notifyByFrom && notifyByFrom->notifySettingsUnknown()) {
Auth().api().requestNotifySetting(notifyByFrom);
}
Auth().api().requestNotifySetting(history->peer);
@ -167,16 +173,17 @@ void System::clearAllFast() {
}
void System::checkDelayed() {
int32 t = unixtime();
for (auto i = _settingWaiters.begin(); i != _settingWaiters.end();) {
auto history = i.key();
bool loaded = false, muted = false;
if (history->peer->notify != UnknownNotifySettings) {
if (history->peer->notify == EmptyNotifySettings || history->peer->notify->mute <= t) {
const auto history = i.key();
const auto peer = history->peer;
auto loaded = false;
auto muted = false;
if (!peer->notifySettingsUnknown()) {
if (!peer->isMuted()) {
loaded = true;
} else if (PeerData *from = i.value().notifyByFrom) {
if (from->notify != UnknownNotifySettings) {
if (from->notify == EmptyNotifySettings || from->notify->mute <= t) {
} else if (const auto from = i.value().notifyByFrom) {
if (!from->notifySettingsUnknown()) {
if (!from->isMuted()) {
loaded = true;
} else {
loaded = muted = true;
@ -187,7 +194,10 @@ void System::checkDelayed() {
}
}
if (loaded) {
if (HistoryItem *item = App::histItemById(history->channelId(), i.value().msg)) {
const auto fullId = FullMsgId(
history->channelId(),
i.value().msg);
if (const auto item = App::histItemById(fullId)) {
if (!item->notificationReady()) {
loaded = false;
}
@ -216,14 +226,18 @@ void System::showNext() {
int32 now = unixtime();
for (auto i = _whenAlerts.begin(); i != _whenAlerts.end();) {
while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
NotifySettingsPtr n = i.key()->peer->notify, f = i.value().begin().value() ? i.value().begin().value()->notify : UnknownNotifySettings;
while (!i.value().isEmpty() && i.value().begin().key() <= ms + 500) { // not more than one sound in 500ms from one peer - grouping
i.value().erase(i.value().begin());
const auto peer = i.key()->peer;
const auto peerUnknown = peer->notifySettingsUnknown();
const auto peerAlert = peerUnknown ? false : !peer->isMuted();
const auto from = i.value().begin().value();
const auto fromUnknown = (!from || from->notifySettingsUnknown());
const auto fromAlert = fromUnknown ? false : !from->isMuted();
if (peerAlert || fromAlert) {
alert = true;
}
if (n == EmptyNotifySettings || (n != UnknownNotifySettings && n->mute <= now)) {
alert = true;
} else if (f == EmptyNotifySettings || (f != UnknownNotifySettings && f->mute <= now)) { // notify by from()
alert = true;
while (!i.value().isEmpty()
&& i.value().begin().key() <= ms + kMinimalAlertDelay) {
i.value().erase(i.value().begin());
}
}
if (i.value().isEmpty()) {

View File

@ -238,17 +238,19 @@ void Filler::addNotifications() {
if (!peer->isMuted()) {
Ui::show(Box<MuteSettingsBox>(peer));
} else {
App::main()->updateNotifySetting(
App::main()->updateNotifySettings(
peer,
NotifySettingSetNotify);
Data::NotifySettings::MuteChange::Unmute);
}
});
auto lifetime = Notify::PeerUpdateViewer(
_peer,
Notify::PeerUpdate::Flag::NotificationsEnabled)
| rpl::start_with_next([=] {
muteAction->setText(muteText(peer->isMuted()));
| rpl::map([=] { return peer->isMuted(); })
| rpl::distinct_until_changed()
| rpl::start_with_next([=](bool muted) {
muteAction->setText(muteText(muted));
});
Ui::AttachAsChild(muteAction, std::move(lifetime));

View File

@ -159,6 +159,8 @@
<(src_loc)/data/data_drafts.h
<(src_loc)/data/data_flags.h
<(src_loc)/data/data_game.h
<(src_loc)/data/data_notify_settings.cpp
<(src_loc)/data/data_notify_settings.h
<(src_loc)/data/data_peer.cpp
<(src_loc)/data/data_peer.h
<(src_loc)/data/data_peer_values.cpp