diff --git a/Telegram/Resources/colors.palette b/Telegram/Resources/colors.palette index b675ff809d..863e1a71da 100644 --- a/Telegram/Resources/colors.palette +++ b/Telegram/Resources/colors.palette @@ -304,6 +304,7 @@ historyPeer8NameFgSelected: historyPeer8NameFg; // orange group member name in a historyPeer8UserpicBg: #faa774; // orange userpic background historyPeerUserpicFg: windowFgActive; // default userpic initials historyPeerSavedMessagesBg: historyPeer4UserpicBg; // saved messages userpic background +historyPeerArchiveUserpicBg: historyPeer2UserpicBg; // archive folder userpic background // Some values are marked as (adjusted), it means they're adjusted by // hue and saturation of the average background color if user chooses diff --git a/Telegram/Resources/icons/archive_userpic.png b/Telegram/Resources/icons/archive_userpic.png new file mode 100644 index 0000000000..00d2d7347c Binary files /dev/null and b/Telegram/Resources/icons/archive_userpic.png differ diff --git a/Telegram/Resources/icons/archive_userpic@2x.png b/Telegram/Resources/icons/archive_userpic@2x.png new file mode 100644 index 0000000000..a1b6aee6f0 Binary files /dev/null and b/Telegram/Resources/icons/archive_userpic@2x.png differ diff --git a/Telegram/Resources/icons/archive_userpic@3x.png b/Telegram/Resources/icons/archive_userpic@3x.png new file mode 100644 index 0000000000..fb77161efe Binary files /dev/null and b/Telegram/Resources/icons/archive_userpic@3x.png differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 9c4b5adb6e..1d70d961f9 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1192,6 +1192,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_channel_mute" = "Mute"; "lng_channel_unmute" = "Unmute"; "lng_saved_messages" = "Saved Messages"; +"lng_archived_chats" = "Archived chats"; "lng_saved_short" = "Save"; "lng_saved_forward_here" = "Forward messages here for quick access"; @@ -1267,7 +1268,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_view_profile" = "View profile"; "lng_context_view_group" = "View group info"; "lng_context_view_channel" = "View channel info"; -"lng_context_view_feed_info" = "View feed info"; +//"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"; @@ -1686,32 +1687,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_admin_log_admin_pin_messages" = "Pin messages"; "lng_admin_log_admin_add_admins" = "Add new admins"; -"lng_feed_name" = "Feed"; -"lng_feed_show_next" = "Show Next"; +// #feed +//"lng_feed_name" = "Feed"; +//"lng_feed_show_next" = "Show Next"; -"lng_feed_group" = "Group in feed"; -"lng_feed_ungroup" = "Ungroup from feed"; -"lng_feed_channel_added" = "Channel added to your feed."; -"lng_feed_channel_removed" = "Channel removed from your feed."; -"lng_feed_no_messages" = "No messages in this feed yet"; -"lng_feed_channels#one" = "{count} channel"; -"lng_feed_channels#other" = "{count} channels"; -"lng_feed_notifications" = "Feed notifications"; -"lng_feed_ungroup_all" = "Ungroup all channels"; -"lng_feed_sure_ungroup_all" = "Are you sure you want to ungroup all channels from this feed?"; -"lng_feed_ungroup_sure" = "Ungroup"; -"lng_feed_create_new" = "New feed"; -"lng_feed_too_few_channels#one" = "You need at least {count} channel to create a feed."; -"lng_feed_too_few_channels#other" = "You need at least {count} channels to create a feed."; -"lng_feed_select_more_channels#one" = "Select {count} channel or more."; -"lng_feed_select_more_channels#other" = "Select {count} channels or more."; -"lng_feed_create" = "Create"; -"lng_feed_edit_title" = "Edit feed"; -"lng_feed_channels_not_found" = "No channels found"; +//"lng_feed_group" = "Group in feed"; +//"lng_feed_ungroup" = "Ungroup from feed"; +//"lng_feed_channel_added" = "Channel added to your feed."; +//"lng_feed_channel_removed" = "Channel removed from your feed."; +//"lng_feed_no_messages" = "No messages in this feed yet"; +//"lng_feed_channels#one" = "{count} channel"; +//"lng_feed_channels#other" = "{count} channels"; +//"lng_feed_notifications" = "Feed notifications"; +//"lng_feed_ungroup_all" = "Ungroup all channels"; +//"lng_feed_sure_ungroup_all" = "Are you sure you want to ungroup all channels from this feed?"; +//"lng_feed_ungroup_sure" = "Ungroup"; +//"lng_feed_create_new" = "New feed"; +//"lng_feed_too_few_channels#one" = "You need at least {count} channel to create a feed."; +//"lng_feed_too_few_channels#other" = "You need at least {count} channels to create a feed."; +//"lng_feed_select_more_channels#one" = "Select {count} channel or more."; +//"lng_feed_select_more_channels#other" = "Select {count} channels or more."; +//"lng_feed_create" = "Create"; +//"lng_feed_edit_title" = "Edit feed"; +//"lng_feed_channels_not_found" = "No channels found"; -"lng_info_feed_title" = "Feed Info"; -"lng_info_feed_is_default" = "Group new channels"; -"lng_info_feed_channels" = "Channels"; +//"lng_info_feed_title" = "Feed Info"; +//"lng_info_feed_is_default" = "Group new channels"; +//"lng_info_feed_channels" = "Channels"; "lng_terms_signup" = "By signing up,\nyou agree to the {link}."; "lng_terms_signup_link" = "Terms of Service"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 11172e889a..9507261418 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -433,38 +433,39 @@ void ApiWrap::savePinnedOrder() { MTP_vector(peers) )).send(); } + +void ApiWrap::toggleHistoryArchived( + not_null history, + bool archived, + Fn callback) { + if (const auto already = _historyArchivedRequests.take(history)) { + request(already->first).cancel(); + } + // #TODO archive + const auto folderId = Data::Folder::kId; + //const auto flags = group + // ? MTPchannels_ChangeFeedBroadcast::Flag::f_feed_id + // : MTPchannels_ChangeFeedBroadcast::Flag(0); + //const auto requestId = request(MTPchannels_ChangeFeedBroadcast( + // MTP_flags(flags), + // channel->inputChannel, + // MTP_int(feedId) + //)).done([=](const MTPUpdates &result) { + // applyUpdates(result); + // if (group) { + // channel->setFeed(_session->data().feed(feedId)); + // } else { + // channel->clearFeed(); + // } + // if (const auto data = _channelGroupingRequests.take(channel)) { + // data->second(); + // } + //}).fail([=](const RPCError &error) { + // _channelGroupingRequests.remove(channel); + //}).send(); + //_channelGroupingRequests.emplace(channel, requestId, callback); +} // #feed -//void ApiWrap::toggleChannelGrouping( -// not_null channel, -// bool group, -// Fn callback) { -// if (const auto already = _channelGroupingRequests.take(channel)) { -// request(already->first).cancel(); -// } -// const auto feedId = Data::Feed::kId; -// const auto flags = group -// ? MTPchannels_ChangeFeedBroadcast::Flag::f_feed_id -// : MTPchannels_ChangeFeedBroadcast::Flag(0); -// const auto requestId = request(MTPchannels_ChangeFeedBroadcast( -// MTP_flags(flags), -// channel->inputChannel, -// MTP_int(feedId) -// )).done([=](const MTPUpdates &result) { -// applyUpdates(result); -// if (group) { -// channel->setFeed(_session->data().feed(feedId)); -// } else { -// channel->clearFeed(); -// } -// if (const auto data = _channelGroupingRequests.take(channel)) { -// data->second(); -// } -// }).fail([=](const RPCError &error) { -// _channelGroupingRequests.remove(channel); -// }).send(); -// _channelGroupingRequests.emplace(channel, requestId, callback); -//} -// //void ApiWrap::ungroupAllFromFeed(not_null feed) { // const auto flags = MTPchannels_SetFeedBroadcasts::Flag::f_channels // | MTPchannels_SetFeedBroadcasts::Flag::f_also_newly_joined; @@ -3597,6 +3598,23 @@ void ApiWrap::applyUpdateNoPtsCheck(const MTPUpdate &update) { Q_UNUSED(d); // Web page was updated anyway. } break; + case mtpc_updateFolderPeers: { + const auto &data = update.c_updateFolderPeers(); + auto &owner = _session->data(); + for (const auto &peer : data.vfolder_peers.v) { + peer.match([&](const MTPDfolderPeer &data) { + const auto peerId = peerFromMTP(data.vpeer); + if (const auto history = owner.historyLoaded(peerId)) { + if (const auto folderId = data.vfolder_id.v) { + history->setFolder(owner.folder(folderId)); + } else { + history->clearFolder(); + } + } + }); + } + } break; + case mtpc_updateDeleteMessages: { auto &d = update.c_updateDeleteMessages(); App::feedWereDeleted(NoChannel, d.vmessages.v); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 78e7c63ad2..6e93e91fcd 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -65,11 +65,11 @@ public: void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0); void savePinnedOrder(); - //void toggleChannelGrouping( // #feed - // not_null channel, - // bool group, - // Fn callback); - //void ungroupAllFromFeed(not_null feed); + void toggleHistoryArchived( + not_null history, + bool archived, + Fn callback); + //void ungroupAllFromFeed(not_null feed); // #feed using RequestMessageDataCallback = Fn; void requestMessageData( @@ -651,8 +651,8 @@ private: Fn _channelMembersForAddCallback; base::flat_map< - not_null, - std::pair>> _channelGroupingRequests; + not_null, + std::pair>> _historyArchivedRequests; using KickRequest = std::pair< not_null, diff --git a/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py b/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py index cbab7e0a1c..9e64b39e9a 100644 --- a/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py +++ b/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py @@ -49,6 +49,7 @@ addChildParentFlags('MTPDreplyKeyboardForceReply', 'MTPDreplyKeyboardMarkup'); addChildParentFlags('MTPDinputPeerNotifySettings', 'MTPDpeerNotifySettings'); addChildParentFlags('MTPDpeerNotifySettings', 'MTPDinputPeerNotifySettings'); addChildParentFlags('MTPDchannelForbidden', 'MTPDchannel'); +addChildParentFlags('MTPDdialogFolder', 'MTPDdialog'); # this is a map (key flags -> map (flag name -> flag bit)) # each key flag of parentFlags should be a subset of the value flag here diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index e53dc3a361..b58b87577b 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -306,27 +306,6 @@ void ChannelData::setAvailableMinId(MsgId availableMinId) { } } } -// #TODO archive -//void ChannelData::setFeed(not_null feed) { -// setFeedPointer(feed); -//} -// -//void ChannelData::clearFeed() { -// setFeedPointer(nullptr); -//} -// -//void ChannelData::setFeedPointer(Data::Feed *feed) { -// if (_feed != feed) { -// const auto was = _feed; -// _feed = feed; -// if (was) { -// was->unregisterOne(this); -// } -// if (_feed) { -// _feed->registerOne(this); -// } -// } -//} bool ChannelData::canBanMembers() const { return amCreator() diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp index f724eceffd..6940974243 100644 --- a/Telegram/SourceFiles/data/data_folder.cpp +++ b/Telegram/SourceFiles/data/data_folder.cpp @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "auth_session.h" #include "apiwrap.h" #include "mainwidget.h" +#include "styles/style_dialogs.h" // st::dialogsArchiveUserpic namespace Data { @@ -35,7 +36,7 @@ Folder::Folder(not_null owner, FolderId id) : Entry(this) , _id(id) , _owner(owner) -, _name(lang(lng_feed_name)) { +, _name(lang(lng_archived_chats)) { indexNameParts(); } @@ -77,83 +78,83 @@ void Folder::indexNameParts() { } } -void Folder::registerOne(not_null peer) { - const auto history = owner().history(peer); - if (!base::contains(_chats, history)) { - const auto invisible = empty(_chats); - _chats.push_back(history); - //session().storage().invalidate( // #feed - // Storage::FeedMessagesInvalidate(_id)); +void Folder::registerOne(not_null history) { + if (base::contains(_histories, history)) { + return; + } + const auto invisible = empty(_histories); + _histories.push_back(history); + //session().storage().invalidate( // #feed + // Storage::FeedMessagesInvalidate(_id)); - if (history->chatListMessageKnown()) { - if (const auto last = history->chatListMessage()) { - if (justUpdateChatListMessage(last)) { - updateChatListEntry(); - } - } - } else if (chatListMessageKnown()) { - history->requestChatListMessage(); - } - if (unreadCountKnown()) { - if (history->unreadCountKnown()) { - // If history unreadCount is known that means that we've - // already had the channel information and if it was in the - // feed already (not yet known) it wouldn't get here. - // That means here we get if we add a new channel to feed. - if (const auto count = history->unreadCount()) { - unreadCountChanged(count, history->mute() ? count : 0); - } - } else if (!_settingChats) { - session().api().requestDialogEntry(this); + if (history->chatListMessageKnown()) { + if (const auto last = history->chatListMessage()) { + if (justUpdateChatListMessage(last)) { + updateChatListEntry(); } } - if (invisible && !empty(_chats)) { - updateChatListExistence(); - for (const auto history : _chats) { - history->updateChatListExistence(); + } else if (chatListMessageKnown()) { + history->requestChatListMessage(); + } + if (unreadCountKnown()) { + if (history->unreadCountKnown()) { + // If history unreadCount is known that means that we've + // already had the channel information and if it was in the + // feed already (not yet known) it wouldn't get here. + // That means here we get if we add a new channel to feed. + if (const auto count = history->unreadCount()) { + unreadCountChanged(count, history->mute() ? count : 0); } - } else { + } else if (!_settingHistories) { + session().api().requestDialogEntry(this); + } + } + if (invisible && !empty(_histories)) { + updateChatListExistence(); + for (const auto history : _histories) { history->updateChatListExistence(); } - _owner->notifyFolderUpdated(this, FolderUpdateFlag::List); + } else { + history->updateChatListExistence(); } + _owner->notifyFolderUpdated(this, FolderUpdateFlag::List); } -void Folder::unregisterOne(not_null peer) { - const auto history = owner().history(peer); - const auto i = ranges::remove(_chats, history); - if (i != end(_chats)) { - const auto visible = !empty(_chats); - _chats.erase(i, end(_chats)); - //session().storage().remove( // #feed - // Storage::FeedMessagesRemoveAll(_id, channel->bareId())); +void Folder::unregisterOne(not_null history) { + const auto i = ranges::remove(_histories, history); + if (i == end(_histories)) { + return; + } + const auto visible = !empty(_histories); + _histories.erase(i, end(_histories)); + //session().storage().remove( // #feed + // Storage::FeedMessagesRemoveAll(_id, channel->bareId())); - if (chatListMessageKnown()) { - if (const auto last = chatListMessage()) { - if (last->history() == history) { - recountChatListMessage(); - } + if (chatListMessageKnown()) { + if (const auto last = chatListMessage()) { + if (last->history() == history) { + recountChatListMessage(); } } - if (unreadCountKnown()) { - if (history->unreadCountKnown()) { - if (const auto delta = -history->unreadCount()) { - unreadCountChanged(delta, history->mute() ? delta : 0); - } - } else { - session().api().requestDialogEntry(this); - } - } - if (visible && empty(_chats)) { - updateChatListExistence(); - for (const auto history : _chats) { - history->updateChatListExistence(); + } + if (unreadCountKnown()) { + if (history->unreadCountKnown()) { + if (const auto delta = -history->unreadCount()) { + unreadCountChanged(delta, history->mute() ? delta : 0); } } else { + session().api().requestDialogEntry(this); + } + } + if (visible && empty(_histories)) { + updateChatListExistence(); + for (const auto history : _histories) { history->updateChatListExistence(); } - _owner->notifyFolderUpdated(this, FolderUpdateFlag::List); + } else { + history->updateChatListExistence(); } + _owner->notifyFolderUpdated(this, FolderUpdateFlag::List); } void Folder::updateChatListMessage(not_null item) { @@ -167,7 +168,7 @@ void Folder::updateChatListMessage(not_null item) { void Folder::loadUserpic() { //constexpr auto kPaintUserpicsCount = 4; // #feed //auto load = kPaintUserpicsCount; - //for (const auto history : _chats) { + //for (const auto history : _histories) { // history->peer->loadUserpic(); // if (!--load) { // break; @@ -180,10 +181,17 @@ void Folder::paintUserpic( int x, int y, int size) const { + p.setPen(Qt::NoPen); + p.setBrush(st::historyPeerArchiveUserpicBg); + { + PainterHighQualityEnabler hq(p); + p.drawRoundedRect(x, y, size, size, size / 3., size / 3.); + } + st::dialogsArchiveUserpic.paintInCenter(p, { x, y, size, size }); //const auto small = (size - st::lineWidth) / 2; // #feed //const auto delta = size - small; //auto index = 0; - //for (const auto history : _chats) { + //for (const auto history : _histories) { // history->peer->paintUserpic(p, x, y, small); // switch (++index) { // case 1: @@ -194,76 +202,76 @@ void Folder::paintUserpic( //} } -const std::vector> &Folder::chats() const { - return _chats; +const std::vector> &Folder::histories() const { + return _histories; } -int32 Folder::chatsHash() const { - const auto ordered = ranges::view::all( - _chats - ) | ranges::view::transform([](not_null history) { - return history->peer->bareId(); - }) | ranges::to_vector | ranges::action::sort; - return Api::CountHash(ordered); +bool Folder::historiesLoaded() const { + return _historiesLoaded; } -bool Folder::chatsLoaded() const { - return _chatsLoaded; -} - -void Folder::setChatsLoaded(bool loaded) { - if (_chatsLoaded != loaded) { - _chatsLoaded = loaded; +void Folder::setHistoriesLoaded(bool loaded) { + if (_historiesLoaded != loaded) { + _historiesLoaded = loaded; _owner->notifyFolderUpdated(this, FolderUpdateFlag::List); } } - -void Folder::setChats(std::vector> chats) { - const auto remove = ranges::view::all( - _chats - ) | ranges::view::transform([](not_null history) { - return history->peer; - }) | ranges::view::filter([&](not_null peer) { - return !base::contains(chats, peer); - }) | ranges::to_vector; - - const auto add = ranges::view::all( - chats - ) | ranges::view::filter([&](not_null peer) { - return ranges::find( - _chats, - peer, - [](auto history) { return history->peer; } - ) == end(_chats); - }) | ranges::view::transform([](PeerData *peer) { - return not_null(peer); - }) | ranges::to_vector; - - changeChatsList(add, remove); - - setChatsLoaded(true); -} - -void Folder::changeChatsList( - const std::vector> &add, - const std::vector> &remove) { - _settingChats = true; - const auto restore = gsl::finally([&] { _settingChats = false; }); - - //for (const auto channel : remove) { // #TODO archive - // channel->clearFeed(); - //} - - //// We assume the last message was correct before requesting the list. - //// So we save it and don't allow channels from the list to change it. - //// After that we restore it. - const auto oldChatListMessage = base::take(_chatListMessage); - //for (const auto channel : add) { - // _chatListMessage = std::nullopt; - // channel->setFeed(this); - //} - _chatListMessage = oldChatListMessage; -} +// // #feed +//int32 Folder::chatsHash() const { +// const auto ordered = ranges::view::all( +// _histories +// ) | ranges::view::transform([](not_null history) { +// return history->peer->bareId(); +// }) | ranges::to_vector | ranges::action::sort; +// return Api::CountHash(ordered); +//} +// +//void Folder::setChats(std::vector> chats) { +// const auto remove = ranges::view::all( +// _histories +// ) | ranges::view::transform([](not_null history) { +// return history->peer; +// }) | ranges::view::filter([&](not_null peer) { +// return !base::contains(chats, peer); +// }) | ranges::to_vector; +// +// const auto add = ranges::view::all( +// chats +// ) | ranges::view::filter([&](not_null peer) { +// return ranges::find( +// _histories, +// peer, +// [](auto history) { return history->peer; } +// ) == end(_histories); +// }) | ranges::view::transform([](PeerData *peer) { +// return not_null(peer); +// }) | ranges::to_vector; +// +// changeChatsList(add, remove); +// +// setChatsLoaded(true); +//} +// +//void Folder::changeChatsList( +// const std::vector> &add, +// const std::vector> &remove) { +// _settingChats = true; +// const auto restore = gsl::finally([&] { _settingChats = false; }); +// +// for (const auto channel : remove) { +// channel->clearFeed(); +// } +// +// //// We assume the last message was correct before requesting the list. +// //// So we save it and don't allow channels from the list to change it. +// //// After that we restore it. +// const auto oldChatListMessage = base::take(_chatListMessage); +// for (const auto channel : add) { +// _chatListMessage = std::nullopt; +// channel->setFeed(this); +// } +// _chatListMessage = oldChatListMessage; +//} bool Folder::justUpdateChatListMessage(not_null item) { if (!_chatListMessage) { @@ -298,7 +306,7 @@ void Folder::requestChatListMessage() { void Folder::recountChatListMessage() { _chatListMessage = std::nullopt; - for (const auto history : _chats) { + for (const auto history : _histories) { if (!history->chatListMessageKnown()) { requestChatListMessage(); return; @@ -309,7 +317,7 @@ void Folder::recountChatListMessage() { void Folder::setChatListMessageFromChannels() { _chatListMessage = nullptr; - for (const auto history : _chats) { + for (const auto history : _histories) { if (const auto last = history->chatListMessage()) { justUpdateChatListMessage(last); } @@ -336,36 +344,38 @@ rpl::producer Folder::unreadCountValue() const { bool Folder::unreadCountKnown() const { return !!_unreadCount; } -// #feed -//void Folder::applyDialog(const MTPDdialogFeed &data) { -// const auto addChannel = [&](ChannelId channelId) { -// if (const auto channel = owner().channelLoaded(channelId)) { -// channel->setFeed(this); -// } -// }; -// for (const auto &channelId : data.vfeed_other_channels.v) { -// addChannel(channelId.v); -// } -// -// _chatListMessage = nullptr; -// if (const auto peerId = peerFromMTP(data.vpeer)) { -// if (const auto channelId = peerToChannel(peerId)) { -// addChannel(channelId); -// const auto fullId = FullMsgId(channelId, data.vtop_message.v); -// if (const auto item = App::histItemById(fullId)) { -// justUpdateChatListMessage(item); -// } -// } -// } -// updateChatListDate(); -// -// setUnreadCounts( -// data.vunread_count.v, -// data.vunread_muted_count.v); -// if (data.has_read_max_position()) { -// setUnreadPosition(FeedPositionFromMTP(data.vread_max_position)); -// } -//} + +void Folder::applyDialog(const MTPDdialogFolder &data) { + //const auto addChannel = [&](ChannelId channelId) { // #feed + // if (const auto channel = owner().channelLoaded(channelId)) { + // channel->setFeed(this); + // } + //}; + //for (const auto &channelId : data.vfeed_other_channels.v) { + // addChannel(channelId.v); + //} + + _chatListMessage = nullptr; + if (const auto peerId = peerFromMTP(data.vpeer)) { + owner().history(peerId)->setFolder(this); + const auto fullId = FullMsgId( + peerToChannel(peerId), + data.vtop_message.v); + if (const auto item = App::histItemById(fullId)) { + justUpdateChatListMessage(item); + } + } + updateChatListDate(); + setUnreadCounts( + data.vunread_unmuted_messages_count.v, + data.vunread_muted_messages_count.v); + //setUnreadMark(data.is_unread_mark()); + //setUnreadMentionsCount(data.vunread_mentions_count.v); + + //if (data.has_read_max_position()) { // #feed + // setUnreadPosition(FeedPositionFromMTP(data.vread_max_position)); + //} +} void Folder::changedInChatListHook(Dialogs::Mode list, bool added) { if (list != Dialogs::Mode::All) { @@ -444,12 +454,12 @@ void Folder::setUnreadCounts(int unreadNonMutedCount, int unreadMutedCount) { _unreadMutedCount = unreadMutedCount; }); } - -void Folder::setUnreadPosition(const MessagePosition &position) { - if (_unreadPosition.current() < position) { - _unreadPosition = position; - } -} +// #feed +//void Folder::setUnreadPosition(const MessagePosition &position) { +// if (_unreadPosition.current() < position) { +// _unreadPosition = position; +// } +//} void Folder::unreadCountChanged(int unreadCountDelta, int mutedCountDelta) { if (!unreadCountKnown()) { @@ -466,14 +476,38 @@ void Folder::unreadCountChanged(int unreadCountDelta, int mutedCountDelta) { _unreadMutedCount += mutedCountDelta; }); } - -MessagePosition Folder::unreadPosition() const { - return _unreadPosition.current(); -} - -rpl::producer Folder::unreadPositionChanges() const { - return _unreadPosition.changes(); -} +// +//void Folder::setUnreadMark(bool unread) { +// if (_unreadMark != unread) { +// _unreadMark = unread; +// if (!_unreadCount || !*_unreadCount) { +// if (inChatList(Dialogs::Mode::All)) { +// const auto delta = _unreadMark ? 1 : -1; +// _owner->unreadIncrement(delta, mute()); +// _owner->unreadEntriesChanged( +// delta, +// mute() ? delta : 0); +// +// updateChatListEntry(); +// } +// } +// Notify::peerUpdatedDelayed( +// peer, +// Notify::PeerUpdate::Flag::UnreadViewChanged); +// } +//} +// +//bool Folder::unreadMark() const { +// return _unreadMark; +//} +// #feed +//MessagePosition Folder::unreadPosition() const { +// return _unreadPosition.current(); +//} +// +//rpl::producer Folder::unreadPositionChanges() const { +// return _unreadPosition.changes(); +//} bool Folder::toImportant() const { return false; // TODO feeds workmode @@ -484,7 +518,7 @@ bool Folder::useProxyPromotion() const { } bool Folder::shouldBeInChatList() const { - return !empty(_chats); + return !empty(_histories); } int Folder::chatListUnreadCount() const { diff --git a/Telegram/SourceFiles/data/data_folder.h b/Telegram/SourceFiles/data/data_folder.h index d0df909df4..924ae83472 100644 --- a/Telegram/SourceFiles/data/data_folder.h +++ b/Telegram/SourceFiles/data/data_folder.h @@ -41,22 +41,26 @@ public: AuthSession &session() const; FolderId id() const; - void registerOne(not_null peer); - void unregisterOne(not_null peer); + void registerOne(not_null history); + void unregisterOne(not_null history); void updateChatListMessage(not_null item); void messageRemoved(not_null item); void historyCleared(not_null history); - //void applyDialog(const MTPDdialogFeed &data); // #feed + void applyDialog(const MTPDdialogFolder &data); void setUnreadCounts(int unreadNonMutedCount, int unreadMutedCount); - void setUnreadPosition(const MessagePosition &position); + //void setUnreadPosition(const MessagePosition &position); // #feed void unreadCountChanged( int unreadCountDelta, int mutedCountDelta); rpl::producer unreadCountValue() const; - MessagePosition unreadPosition() const; - rpl::producer unreadPositionChanges() const; + //MessagePosition unreadPosition() const; // #feed + //rpl::producer unreadPositionChanges() const; // #feed + + //void setUnreadMark(bool unread); + //bool unreadMark() const; + //int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0. int unreadCount() const; bool unreadCountKnown() const; @@ -82,11 +86,11 @@ public: int y, int size) const override; - const std::vector> &chats() const; - int32 chatsHash() const; - bool chatsLoaded() const; - void setChatsLoaded(bool loaded); - void setChats(std::vector> chats); + const std::vector> &histories() const; + bool historiesLoaded() const; + void setHistoriesLoaded(bool loaded); + //int32 chatsHash() const; + //void setChats(std::vector> chats); // #feed private: void indexNameParts(); @@ -103,9 +107,9 @@ private: FolderId _id = 0; not_null _owner; - std::vector> _chats; - bool _settingChats = false; - bool _chatsLoaded = false; + std::vector> _histories; + bool _settingHistories = false; + bool _historiesLoaded = false; QString _name; base::flat_set _nameWords; @@ -116,6 +120,7 @@ private: std::optional _unreadCount; rpl::event_stream _unreadCountChanges; int _unreadMutedCount = 0; + //bool _unreadMark = false; }; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index c0174beb45..0072fdd6d5 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1281,8 +1281,8 @@ void Session::applyPinnedDialogs(const QVector &list) { if (const auto peer = peerFromMTP(data.vpeer)) { setPinnedDialog(history(peer), true); } - }, [&](const MTPDdialogFolder &data) { // #TODO archive - //setPinnedDialog(processFolder(data.vfolder), true); + }, [&](const MTPDdialogFolder &data) { + setPinnedDialog(processFolder(data.vfolder), true); }); } } @@ -1294,9 +1294,9 @@ void Session::applyPinnedDialogs(const QVector &list) { if (const auto peerId = peerFromMTP(data.vpeer)) { setPinnedDialog(history(peerId), true); } - }, [&](const MTPDdialogPeerFolder &data) { // #TODO archive - //const auto folderId = data.vfolder_id.v; - //setPinnedDialog(folder(folderId), true); + }, [&](const MTPDdialogPeerFolder &data) { + const auto folderId = data.vfolder_id.v; + setPinnedDialog(folder(folderId), true); }); } } @@ -2801,6 +2801,21 @@ Folder *Session::folderLoaded(FolderId id) { const auto it = _folders.find(id); return (it == end(_folders)) ? nullptr : it->second.get(); } + +not_null Session::processFolder(const MTPFolder &data) { + return data.match([&](const MTPDfolder &data) { + return processFolder(data); + }); +} + +not_null Session::processFolder(const MTPDfolder &data) { + const auto result = folder(data.vid.v); + //if (data.has_photo()) { + // data.vphoto; + //} + //data.vtitle; + return result; +} // // #feed //void Session::setDefaultFeedId(FeedId id) { // _defaultFeedId = id; diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index a56cc610ee..2eeabe1062 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -154,6 +154,7 @@ dialogsBotIconActive: icon {{ "dialogs_bot", dialogsChatIconFgActive, point(1px, //dialogsFeedIcon: icon {{ "dialogs_feed", dialogsChatIconFg, point(4px, 4px) }}; // #feed //dialogsFeedIconOver: icon {{ "dialogs_feed", dialogsChatIconFgOver, point(4px, 4px) }}; //dialogsFeedIconActive: icon {{ "dialogs_feed", dialogsChatIconFgActive, point(4px, 4px) }}; +dialogsArchiveUserpic: icon {{ "archive_userpic", historyPeerUserpicFg }}; dialogsSendStateSkip: 20px; dialogsSendingIcon: icon {{ "dialogs_sending", dialogsSendingIconFg, point(8px, 4px) }}; diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.h b/Telegram/SourceFiles/dialogs/dialogs_entry.h index c885ff33ce..6804a2d0b3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.h +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.h @@ -36,6 +36,9 @@ struct PositionChange { class Entry { public: Entry(const Key &key); + Entry(const Entry &other) = delete; + Entry &operator=(const Entry &other) = delete; + virtual ~Entry() = default; PositionChange adjustByPosInChatList( Mode list, @@ -100,8 +103,6 @@ public: return _timeId; } - virtual ~Entry() = default; - mutable const HistoryItem *textCachedFor = nullptr; // cache mutable Text lastItemTextCache; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 55129fa150..7be88e3ce2 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -108,11 +108,11 @@ DialogsInner::DialogsInner(QWidget *parent, not_null contro if (history->textCachedFor == item) { history->updateChatListEntry(); } - //if (const auto folder = history->peer->folder()) { // #TODO archive - // if (folder->textCachedFor == item) { - // folder->updateChatListEntry(); - // } - //} + if (const auto folder = history->folder()) { + if (folder->textCachedFor == item) { + folder->updateChatListEntry(); + } + } }, lifetime()); Auth().data().sendActionAnimationUpdated( @@ -1601,13 +1601,13 @@ void DialogsInner::contextMenuEvent(QContextMenuEvent *e) { }, Window::PeerMenuSource::ChatsList); } else if (const auto folder = row.key.folder()) { - //Window::FillFolderMenu( // #TODO archive - // _controller, - // folder, - // [&](const QString &text, Fn callback) { - // return _menu->addAction(text, std::move(callback)); - // }, - // Window::PeerMenuSource::ChatsList); + Window::FillFolderMenu( + _controller, + folder, + [&](const QString &text, Fn callback) { + return _menu->addAction(text, std::move(callback)); + }, + Window::PeerMenuSource::ChatsList); } connect(_menu.get(), &QObject::destroyed, [=] { if (_menuRow.key) { @@ -1853,7 +1853,7 @@ void DialogsInner::dialogsReceived(const QVector &added) { dialog.match([&](const MTPDdialog &data) { applyDialog(data); }, [&](const MTPDdialogFolder &data) { - //applyFolderDialog(data); // #TODO archive + applyFolderDialog(data); }); } refresh(); @@ -1885,19 +1885,18 @@ void DialogsInner::applyDialog(const MTPDdialog &dialog) { } } } -// #feed -//void DialogsInner::applyFeedDialog(const MTPDdialogFeed &dialog) { -// const auto feedId = dialog.vfeed_id.v; -// const auto feed = Auth().data().feed(feedId); -// feed->applyDialog(dialog); -// -// if (!feed->useProxyPromotion() && !feed->isPinnedDialog()) { -// const auto date = feed->chatListDate(); -// if (!date.isNull()) { -// addSavedPeersAfter(date); -// } -// } -//} + +void DialogsInner::applyFolderDialog(const MTPDdialogFolder &dialog) { + const auto folder = Auth().data().processFolder(dialog.vfolder); + folder->applyDialog(dialog); + + if (!folder->useProxyPromotion() && !folder->isPinnedDialog()) { + const auto date = folder->chatListTimeId(); + if (date != 0) { + addSavedPeersAfter(ParseDateTime(date)); + } + } +} void DialogsInner::addSavedPeersAfter(const QDateTime &date) { auto &saved = cRefSavedPeersByTime(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index e524dbd137..9fdecf58b7 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -202,7 +202,7 @@ private: Dialogs::RowDescriptor chatListEntryLast() const; void applyDialog(const MTPDdialog &dialog); -// void applyFeedDialog(const MTPDdialogFeed &dialog); // #feed + void applyFolderDialog(const MTPDdialogFolder &dialog); void itemRemoved(not_null item); enum class UpdateRowSection { diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index ed285bbaab..d2115076c4 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1603,7 +1603,7 @@ int History::unreadCount() const { return _unreadCount ? *_unreadCount : 0; } -int History::historiesUnreadCount() const { +int History::unreadCountForBadge() const { const auto result = unreadCount(); return (!result && unreadMark()) ? 1 : result; } @@ -1745,7 +1745,7 @@ bool History::changeMute(bool newMute) { // } //} if (inChatList(Dialogs::Mode::All)) { - if (const auto count = historiesUnreadCount()) { + if (const auto count = unreadCountForBadge()) { _owner->unreadMuteChanged(count, _mute); const auto entriesWithUnreadDelta = 0; @@ -1807,6 +1807,32 @@ std::shared_ptr History::adminLogIdManager() { return result; } +Data::Folder *History::folder() const { + return _folder; +} + +void History::setFolder(not_null folder) { + setFolderPointer(folder); +} + +void History::clearFolder() { + setFolderPointer(nullptr); +} + +void History::setFolderPointer(Data::Folder *folder) { + if (_folder != folder) { + const auto was = _folder; + _folder = folder; + if (was) { + was->unregisterOne(this); + } + if (_folder) { + _folder->registerOne(this); + } + updateChatListSortPosition(); + } +} + TimeId History::adjustChatListTimeId() const { const auto result = chatListTimeId(); if (const auto draft = cloudDraft()) { @@ -2369,7 +2395,7 @@ bool History::useProxyPromotion() const { } bool History::shouldBeInChatList() const { - if (peer->migrateTo()) { + if (peer->migrateTo() || folder() != nullptr) { return false; } else if (isPinnedDialog()) { return true; @@ -3014,7 +3040,7 @@ void History::applyGroupAdminChanges( void History::changedInChatListHook(Dialogs::Mode list, bool added) { if (list == Dialogs::Mode::All) { - if (const auto delta = historiesUnreadCount() * (added ? 1 : -1)) { + if (const auto delta = unreadCountForBadge() * (added ? 1 : -1)) { _owner->unreadIncrement(delta, mute()); const auto entriesDelta = added ? 1 : -1; diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index e722b552a4..be9c43e3ce 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -28,6 +28,7 @@ class AuthSession; namespace Data { struct Draft; class Session; +class Folder; } // namespace Data namespace Dialogs { @@ -61,6 +62,7 @@ public: History(not_null owner, PeerId peerId); History(const History &) = delete; History &operator=(const History &) = delete; + ~History(); Data::Session &owner() const; AuthSession &session() const; @@ -170,7 +172,7 @@ public: void changeUnreadCount(int delta); void setUnreadMark(bool unread); bool unreadMark() const; - int historiesUnreadCount() const; // unreadCount || unreadMark ? 1 : 0. + int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0. bool mute() const; bool changeMute(bool newMute); void addUnreadBar(); @@ -324,7 +326,9 @@ public: std::shared_ptr adminLogIdManager(); - virtual ~History(); + Data::Folder *folder() const; + void setFolder(not_null folder); + void clearFolder(); // Still public data. std::deque> blocks; @@ -461,6 +465,8 @@ private: void createLocalDraftFromCloud(); + void setFolderPointer(Data::Folder *folder); + not_null _owner; Flags _flags = 0; bool _mute = false; @@ -472,6 +478,8 @@ private: bool _loadedAtTop = false; bool _loadedAtBottom = true; + Data::Folder *_folder = nullptr; + std::optional _inboxReadBefore; std::optional _outboxReadBefore; std::optional _unreadCount; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 5a04bced3c..1a0a5f2a2c 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4014,6 +4014,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { }); } break; + case mtpc_updateFolderPeers: { + const auto &data = update.c_updateFolderPeers(); + + ptsUpdateAndApply(data.vpts.v, data.vpts_count.v, update); + } break; + // Deleted messages. case mtpc_updateDeleteMessages: { auto &d = update.c_updateDeleteMessages(); @@ -4287,8 +4293,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { return !session().data().historyLoaded( peerFromMTP(data.vpeer)); }, [&](const MTPDdialogPeerFolder &data) { - //return !session().data().folderLoaded(data.vfolder_id.v); - return true; // #TODO archive + return !session().data().folderLoaded(data.vfolder_id.v); }); }; const auto allLoaded = ranges::find_if(order, notLoaded) @@ -4317,17 +4322,16 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { _dialogs->loadPinnedDialogs(); } }, [&](const MTPDdialogPeerFolder &data) { - // #TODO archive - //const auto id = data.vfolder_id.v; - //if (const auto folder = session().data().folderLoaded(id)) { - // session().data().setPinnedDialog(folder, d.is_pinned()); - //} else { - // DEBUG_LOG(("API Error: " - // "pinned folder not loaded for feedId %1" - // ).arg(folderId - // )); - // _dialogs->loadPinnedDialogs(); - //} + const auto id = data.vfolder_id.v; + if (const auto folder = session().data().folderLoaded(id)) { + session().data().setPinnedDialog(folder, d.is_pinned()); + } else { + DEBUG_LOG(("API Error: " + "pinned folder not loaded for folderId %1" + ).arg(id + )); + _dialogs->loadPinnedDialogs(); + } }); } break;