Mark [un]read from chats list.

This commit is contained in:
John Preston 2018-06-26 19:03:45 +01:00
parent 372cf275e0
commit 35c759c6bc
15 changed files with 196 additions and 33 deletions

View File

@ -1106,6 +1106,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_view_feed_info" = "View feed info";
"lng_context_pin_to_top" = "Pin to top";
"lng_context_unpin_from_top" = "Unpin from top";
"lng_context_mark_unread" = "Mark as unread";
"lng_context_mark_read" = "Mark as read";
"lng_context_promote_admin" = "Promote to admin";
"lng_context_edit_permissions" = "Edit permissions";

View File

@ -719,6 +719,18 @@ void ApiWrap::applyFeedDialogs(
_session->data().sendHistoryChangeNotifications();
}
void ApiWrap::changeDialogUnreadMark(
not_null<History*> history,
bool unread) {
history->setUnreadMark(unread);
using Flag = MTPmessages_MarkDialogUnread::Flag;
request(MTPmessages_MarkDialogUnread(
MTP_flags(unread ? Flag::f_unread : Flag(0)),
MTP_inputDialogPeer(history->peer->input)
)).send();
}
void ApiWrap::requestFullPeer(PeerData *peer) {
if (!peer || _fullPeerRequests.contains(peer)) return;
@ -4417,6 +4429,9 @@ void ApiWrap::readServerHistory(not_null<History*> history) {
if (history->unreadCount()) {
readServerHistoryForce(history);
}
if (history->unreadMark()) {
changeDialogUnreadMark(history, false);
}
}
void ApiWrap::readServerHistoryForce(not_null<History*> history) {

View File

@ -85,6 +85,8 @@ public:
//void setFeedChannels(
// not_null<Data::Feed*> feed,
// const std::vector<not_null<ChannelData*>> &channels);
void changeDialogUnreadMark(not_null<History*> history, bool unread);
//void changeDialogUnreadMark(not_null<Data::Feed*> feed, bool unread); // #feed
void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer);

View File

@ -455,6 +455,10 @@ int Feed::chatListUnreadCount() const {
return unreadCount();
}
bool Feed::chatListUnreadMark() const {
return false; // #feed unread mark
}
bool Feed::chatListMutedBadge() const {
return _unreadCount ? (*_unreadCount <= _unreadMutedCount) : false;
}

View File

@ -63,6 +63,7 @@ public:
bool toImportant() const override;
bool shouldBeInChatList() const override;
int chatListUnreadCount() const override;
bool chatListUnreadMark() const override;
bool chatListMutedBadge() const override;
HistoryItem *chatsListItem() const override;
const QString &chatsListName() const override;

View File

@ -72,6 +72,7 @@ public:
virtual bool toImportant() const = 0;
virtual bool shouldBeInChatList() const = 0;
virtual int chatListUnreadCount() const = 0;
virtual bool chatListUnreadMark() const = 0;
virtual bool chatListMutedBadge() const = 0;
virtual HistoryItem *chatsListItem() const = 0;
virtual const QString &chatsListName() const = 0;

View File

@ -407,10 +407,11 @@ void RowPainter::paint(
const auto history = row->history();
const auto peer = history ? history->peer.get() : nullptr;
const auto unreadCount = entry->chatListUnreadCount();
const auto unreadMark = entry->chatListUnreadMark();
const auto unreadMuted = entry->chatListMutedBadge();
const auto item = entry->chatsListItem();
const auto cloudDraft = [&]() -> const Data::Draft*{
if (history && (!item || !unreadCount)) {
if (history && (!item || (!unreadCount && !unreadMark))) {
// Draw item, if there are unread messages.
if (const auto draft = history->cloudDraft()) {
if (!Data::draftIsNull(draft)) {
@ -458,11 +459,18 @@ void RowPainter::paint(
}
return (unreadCount > 0);
}();
const auto displayUnreadMark = !displayUnreadCounter
&& !displayMentionBadge
&& history
&& unreadMark;
const auto displayPinnedIcon = !displayUnreadCounter
&& !displayMentionBadge
&& !displayUnreadMark
&& entry->isPinnedDialog();
if (displayUnreadCounter) {
auto counter = QString::number(unreadCount);
if (displayUnreadCounter || displayUnreadMark) {
auto counter = (unreadCount > 0)
? QString::number(unreadCount)
: QString();
auto unreadRight = fullWidth - st::dialogsPadding.x();
auto unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
auto unreadWidth = 0;

View File

@ -1645,6 +1645,11 @@ int History::unreadCount() const {
return _unreadCount ? *_unreadCount : 0;
}
int History::historiesUnreadCount() const {
const auto result = unreadCount();
return (!result && unreadMark()) ? 1 : result;
}
bool History::unreadCountKnown() const {
return !!_unreadCount;
}
@ -1673,6 +1678,16 @@ void History::setUnreadCount(int newUnreadCount) {
calculateFirstUnreadMessage();
}
}
const auto unreadMarkDelta = [&] {
if (_unreadMark) {
const auto was = _unreadCount && (*_unreadCount > 0);
const auto now = (newUnreadCount > 0);
if (was != now) {
return was ? 1 : -1;
}
}
return 0;
}();
_unreadCount = newUnreadCount;
if (_unreadBarView) {
@ -1685,16 +1700,40 @@ void History::setUnreadCount(int newUnreadCount) {
}
if (inChatList(Dialogs::Mode::All)) {
const auto delta = unreadCountDelta
? *unreadCountDelta
: newUnreadCount;
App::histories().unreadIncrement(
unreadCountDelta ? *unreadCountDelta : newUnreadCount,
delta + unreadMarkDelta,
mute());
}
if (const auto main = App::main()) {
main->unreadCountChanged(this);
}
Notify::peerUpdatedDelayed(
peer,
Notify::PeerUpdate::Flag::UnreadViewChanged);
}
}
void History::setUnreadMark(bool unread) {
if (_unreadMark != unread) {
_unreadMark = unread;
if (!_unreadCount || !*_unreadCount) {
if (inChatList(Dialogs::Mode::All)) {
const auto delta = _unreadMark ? 1 : -1;
App::histories().unreadIncrement(delta, mute());
updateChatListEntry();
}
}
Notify::peerUpdatedDelayed(
peer,
Notify::PeerUpdate::Flag::UnreadViewChanged);
}
}
bool History::unreadMark() const {
return _unreadMark;
}
void History::changeUnreadCount(int delta) {
if (_unreadCount) {
setUnreadCount(std::max(*_unreadCount + delta, 0));
@ -1733,8 +1772,8 @@ bool History::changeMute(bool newMute) {
}
}
if (inChatList(Dialogs::Mode::All)) {
if (_unreadCount && *_unreadCount) {
App::histories().unreadMuteChanged(*_unreadCount, _mute);
if (const auto count = historiesUnreadCount()) {
App::histories().unreadMuteChanged(count, _mute);
Notify::unreadCounterUpdated();
}
Notify::historyMuteUpdated(this);
@ -1947,8 +1986,7 @@ not_null<HistoryItem*> History::addNewInTheMiddle(
return item;
}
int History::chatListUnreadCount() const {
const auto result = unreadCount();
History *History::migrateSibling() const {
const auto addFromId = [&] {
if (const auto from = peer->migrateFrom()) {
return from->id;
@ -1957,12 +1995,26 @@ int History::chatListUnreadCount() const {
}
return PeerId(0);
}();
if (const auto migrated = App::historyLoaded(addFromId)) {
return App::historyLoaded(addFromId);
}
int History::chatListUnreadCount() const {
const auto result = unreadCount();
if (const auto migrated = migrateSibling()) {
return result + migrated->unreadCount();
}
return result;
}
bool History::chatListUnreadMark() const {
if (unreadMark()) {
return true;
} else if (const auto migrated = migrateSibling()) {
return migrated->unreadMark();
}
return false;
}
bool History::chatListMutedBadge() const {
return mute();
}
@ -2201,6 +2253,7 @@ void History::applyDialog(const MTPDdialog &data) {
data.vread_inbox_max_id.v,
data.vread_outbox_max_id.v);
applyDialogTopMessage(data.vtop_message.v);
setUnreadMark(data.is_unread_mark());
setUnreadMentionsCount(data.vunread_mentions_count.v);
if (const auto channel = peer->asChannel()) {
if (data.has_pts()) {
@ -2650,9 +2703,10 @@ void History::applyGroupAdminChanges(
}
void History::changedInChatListHook(Dialogs::Mode list, bool added) {
if (list == Dialogs::Mode::All && unreadCount()) {
const auto delta = added ? unreadCount() : -unreadCount();
App::histories().unreadIncrement(delta, mute());
if (list == Dialogs::Mode::All) {
if (const auto delta = historiesUnreadCount() * (added ? 1 : -1)) {
App::histories().unreadIncrement(delta, mute());
}
}
}

View File

@ -213,6 +213,9 @@ public:
bool unreadCountKnown() const;
void setUnreadCount(int newUnreadCount);
void changeUnreadCount(int delta);
void setUnreadMark(bool unread);
bool unreadMark() const;
int historiesUnreadCount() const; // unreadCount || unreadMark ? 1 : 0.
bool mute() const;
bool changeMute(bool newMute);
void addUnreadBar();
@ -322,6 +325,7 @@ public:
HistoryItemsList validateForwardDraft();
void setForwardDraft(MessageIdsList &&items);
History *migrateSibling() const;
bool useProxyPromotion() const override;
void updateChatListExistence() override;
bool shouldBeInChatList() const override;
@ -329,6 +333,7 @@ public:
return !mute();
}
int chatListUnreadCount() const override;
bool chatListUnreadMark() const override;
bool chatListMutedBadge() const override;
HistoryItem *chatsListItem() const override;
const QString &chatsListName() const override;
@ -492,6 +497,7 @@ private:
base::optional<int> _unreadMentionsCount;
base::flat_set<MsgId> _unreadMentions;
base::optional<HistoryItem*> _lastMessage;
bool _unreadMark = false;
// A pointer to the block that is currently being built.
// We hold this pointer so we can destroy it while building

View File

@ -641,6 +641,7 @@ HistoryWidget::HistoryWidget(
using UpdateFlag = Notify::PeerUpdate::Flag;
auto changes = UpdateFlag::ChannelRightsChanged
| UpdateFlag::UnreadMentionsChanged
| UpdateFlag::UnreadViewChanged
| UpdateFlag::MigrationChanged
| UpdateFlag::RestrictionReasonChanged
| UpdateFlag::ChannelPinnedChanged
@ -659,6 +660,9 @@ HistoryWidget::HistoryWidget(
if (update.flags & UpdateFlag::UnreadMentionsChanged) {
updateUnreadMentionsVisibility();
}
if (update.flags & UpdateFlag::UnreadViewChanged) {
unreadCountUpdated();
}
if (update.flags & UpdateFlag::MigrationChanged) {
if (auto channel = _peer->migrateTo()) {
Ui::showPeerHistory(channel, ShowAtUnreadMsgId);
@ -1913,7 +1917,19 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
}
}
}
unreadCountChanged(_history); // set _historyDown badge.
if (_history->chatListUnreadMark()) {
Auth().api().changeDialogUnreadMark(_history, false);
if (_migrated) {
Auth().api().changeDialogUnreadMark(_migrated, false);
}
// Must be done before unreadCountUpdated(), or we auto-close.
_history->setUnreadMark(false);
if (_migrated) {
_migrated->setUnreadMark(false);
}
}
unreadCountUpdated(); // set _historyDown badge.
} else {
_topBar->setActiveChat(Dialogs::Key());
updateTopBarSelection();
@ -2366,8 +2382,15 @@ void HistoryWidget::historyToDown(History *history) {
}
}
void HistoryWidget::unreadCountChanged(not_null<History*> history) {
if (history == _history || history == _migrated) {
void HistoryWidget::unreadCountUpdated() {
if (_history->chatListUnreadMark()) {
crl::on_main(this, [=, history = _history] {
if (history == _history) {
controller()->showBackFromStack();
emit cancelled();
}
});
} else {
updateHistoryDownVisibility();
_historyDown->setUnreadCount(_history->chatListUnreadCount());
}
@ -2376,7 +2399,9 @@ void HistoryWidget::unreadCountChanged(not_null<History*> history) {
bool HistoryWidget::messagesFailed(const RPCError &error, mtpRequestId requestId) {
if (MTP::isDefaultHandledError(error)) return false;
if (error.type() == qstr("CHANNEL_PRIVATE") || error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA") || error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
if (error.type() == qstr("CHANNEL_PRIVATE")
|| error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA")
|| error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
auto was = _peer;
controller()->showBackFromStack();
Ui::show(Box<InformBox>(lang((was && was->isMegagroup()) ? lng_group_not_accessible : lng_channel_not_accessible)));

View File

@ -211,7 +211,6 @@ public:
not_null<History*> history,
not_null<HistoryItem*> item);
void historyToDown(History *history);
void unreadCountChanged(not_null<History*> history);
QRect historyRect() const;
void pushTabbedSelectorToThirdSection(
@ -449,6 +448,7 @@ private:
void forwardItems(MessageIdsList &&items);
void handleHistoryChange(not_null<const History*> history);
void refreshAboutProxyPromotion();
void unreadCountUpdated();
void highlightMessage(MsgId universalMessageId);
void adjustHighlightedMessageToMigrated();

View File

@ -1275,10 +1275,6 @@ Dialogs::IndexedList *MainWidget::contactsNoDialogsList() {
return _dialogs->contactsNoDialogsList();
}
void MainWidget::unreadCountChanged(not_null<History*> history) {
_history->unreadCountChanged(history);
}
TimeMs MainWidget::highlightStartTime(not_null<const HistoryItem*> item) const {
return _history->highlightStartTime(item);
}
@ -4634,8 +4630,14 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateDialogUnreadMark: {
const auto &data = update.c_updateDialogUnreadMark();
if (data.is_unread()) {
// #TODO dialog_unread
const auto history = data.vpeer.match(
[&](const MTPDdialogPeer &data) {
const auto peerId = peerFromMTP(data.vpeer);
return App::historyLoaded(peerId);
//}, [&](const MTPDdialogPeerFeed &data) { // #feed
});
if (history) {
history->setUnreadMark(data.is_unread());
}
} break;

View File

@ -222,8 +222,6 @@ public:
Dialogs::IndexedList *dialogsList();
Dialogs::IndexedList *contactsNoDialogsList();
void unreadCountChanged(not_null<History*> history);
// While HistoryInner is not HistoryView::ListWidget.
TimeMs highlightStartTime(not_null<const HistoryItem*> item) const;
bool historyInSelectionMode() const;

View File

@ -37,13 +37,14 @@ struct PeerUpdate {
MigrationChanged = (1 << 6),
PinnedChanged = (1 << 7),
RestrictionReasonChanged = (1 << 8),
UnreadViewChanged = (1 << 9),
// For chats and channels
InviteLinkChanged = (1 << 9),
MembersChanged = (1 << 10),
AdminsChanged = (1 << 11),
BannedUsersChanged = (1 << 12),
UnreadMentionsChanged = (1 << 13),
InviteLinkChanged = (1 << 10),
MembersChanged = (1 << 11),
AdminsChanged = (1 << 12),
BannedUsersChanged = (1 << 13),
UnreadMentionsChanged = (1 << 14),
// For users
UserCanShareContact = (1 << 16),

View File

@ -50,6 +50,7 @@ private:
void addPinToggle();
void addInfo();
void addSearch();
void addToggleUnreadMark();
void addUserActions(not_null<UserData*> user);
void addBlockUser(not_null<UserData*> user);
void addChatActions(not_null<ChatData*> chat);
@ -229,6 +230,48 @@ void Filler::addSearch() {
});
}
void Filler::addToggleUnreadMark() {
const auto peer = _peer;
const auto isUnread = [](not_null<PeerData*> peer) {
if (const auto history = App::historyLoaded(peer)) {
return (history->chatListUnreadCount() > 0)
|| (history->chatListUnreadMark());
}
return false;
};
const auto label = [=](not_null<PeerData*> peer) {
return lang(isUnread(peer)
? lng_context_mark_read
: lng_context_mark_unread);
};
auto action = _addAction(label(peer), [=] {
const auto markAsRead = isUnread(peer);
const auto handle = [&](not_null<History*> history) {
if (markAsRead) {
Auth().api().readServerHistory(history);
} else {
Auth().api().changeDialogUnreadMark(history, !markAsRead);
}
};
const auto history = App::history(peer);
handle(history);
if (markAsRead) {
if (const auto migrated = history->migrateSibling()) {
handle(migrated);
}
}
});
auto lifetime = Notify::PeerUpdateViewer(
_peer,
Notify::PeerUpdate::Flag::UnreadViewChanged
) | rpl::start_with_next([=] {
action->setText(label(peer));
});
Ui::AttachAsChild(action, std::move(lifetime));
}
void Filler::addBlockUser(not_null<UserData*> user) {
auto blockText = [](not_null<UserData*> user) {
return lang(user->isBlocked()
@ -401,6 +444,7 @@ void Filler::fill() {
}
if (_source == PeerMenuSource::ChatsList) {
addSearch();
addToggleUnreadMark();
}
if (const auto user = _peer->asUser()) {