Allow archive with stories only.

This commit is contained in:
John Preston 2023-07-18 12:15:19 +04:00
parent 35214d108e
commit 4402cce928
17 changed files with 207 additions and 78 deletions

View File

@ -3822,8 +3822,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_userpic_builder_emoji_subtitle" = "Choose sticker or emoji";
"lng_stories_my_name" = "My Story";
"lng_stories_archive" = "Archive";
"lng_stories_unarchive" = "Unarchive";
"lng_stories_archive" = "Hide Stories";
"lng_stories_unarchive" = "Unhide Stories";
"lng_stories_row_count#one" = "{count} Story";
"lng_stories_row_count#other" = "{count} Stories";
"lng_stories_views#one" = "{count} view";
@ -3838,8 +3838,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stories_archive_title" = "Stories Archive";
"lng_stories_archive_about" = "Only you can see archived stories unless you choose to save them to your profile.";
"lng_stories_reply_sent" = "Message Sent";
"lng_stories_hidden_to_contacts" = "Stories of {user} were moved to **Archive**.";
"lng_stories_shown_in_chats" = "Stories of {user} were moved to the **Chats List**.";
"lng_stories_hidden_to_contacts" = "Stories from {user} will now be shown in **Archived Chats**.";
"lng_stories_shown_in_chats" = "Stories from {user} will now be shown in the **Chats List**.";
"lng_stories_delete_one_sure" = "Are you sure you want to delete this story?";
"lng_stories_delete_sure#one" = "Are you sure you want to delete {count} story?";
"lng_stories_delete_sure#other" = "Are you sure you want to delete {count} stories?";

View File

@ -39,6 +39,21 @@ constexpr auto kShowChatNamesCount = 8;
not_null<Folder*> folder) {
const auto &list = folder->lastHistories();
if (list.empty()) {
if (const auto storiesUnread = folder->storiesUnreadCount()) {
return {
tr::lng_contacts_stories_status_new(
tr::now,
lt_count,
storiesUnread),
};
} else if (const auto storiesCount = folder->storiesCount()) {
return {
tr::lng_contacts_stories_status(
tr::now,
lt_count,
storiesCount),
};
}
return {};
}
@ -301,6 +316,33 @@ void Folder::validateListEntryCache() {
Ui::ItemTextDefaultOptions());
}
void Folder::updateStoriesCount(int count, int unread) {
if (_storiesCount == count && _storiesUnreadCount == unread) {
return;
}
const auto limit = (1 << 16) - 1;
const auto was = (_storiesCount > 0);
_storiesCount = std::min(count, limit);
_storiesUnreadCount = std::min(unread, limit);
const auto now = (_storiesCount > 0);
if (was == now) {
updateChatListEntryPostponed();
} else if (now) {
updateChatListSortPosition();
} else {
updateChatListExistence();
}
++_chatListViewVersion;
}
int Folder::storiesCount() const {
return _storiesCount;
}
int Folder::storiesUnreadCount() const {
return _storiesUnreadCount;
}
void Folder::requestChatListMessage() {
if (!chatListMessageKnown()) {
owner().histories().requestDialogEntry(this);
@ -339,7 +381,7 @@ int Folder::fixedOnTopIndex() const {
}
bool Folder::shouldBeInChatList() const {
return !_chatsList.empty();
return !_chatsList.empty() || (_storiesCount > 0);
}
Dialogs::UnreadState Folder::chatListUnreadState() const {

View File

@ -75,6 +75,10 @@ public:
return _listEntryCache;
}
void updateStoriesCount(int count, int unread);
[[nodiscard]] int storiesCount() const;
[[nodiscard]] int storiesUnreadCount() const;
private:
void indexNameParts();
@ -104,6 +108,9 @@ private:
int _chatListViewVersion = 0;
//rpl::variable<MessagePosition> _unreadPosition;
uint16_t _storiesCount = 0;
uint16_t _storiesUnreadCount = 0;
rpl::lifetime _lifetime;
};

View File

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h"
#include "data/data_changes.h"
#include "data/data_document.h"
#include "data/data_folder.h"
#include "data/data_photo.h"
#include "data/data_user.h"
#include "data/data_session.h"
@ -562,6 +563,31 @@ void Stories::preloadListsMore() {
}
}
void Stories::notifySourcesChanged(StorySourcesList list) {
_sourcesChanged[static_cast<int>(list)].fire({});
if (list == StorySourcesList::Hidden) {
pushHiddenCountsToFolder();
}
}
void Stories::pushHiddenCountsToFolder() {
const auto &list = sources(StorySourcesList::Hidden);
if (list.empty()) {
if (_folderForHidden) {
_folderForHidden->updateStoriesCount(0, 0);
}
return;
}
if (!_folderForHidden) {
_folderForHidden = _owner->folder(Folder::kId);
}
const auto count = int(list.size());
const auto unread = ranges::count_if(
list,
[](const StoriesSourceInfo &info) { return info.unreadCount > 0; });
_folderForHidden->updateStoriesCount(count, unread);
}
void Stories::sendResolveRequests() {
if (!_resolveSent.empty()) {
return;
@ -722,7 +748,7 @@ void Stories::applyRemovedFromActive(FullStoryId id) {
&StoriesSourceInfo::id);
if (i != end(sources)) {
sources.erase(i);
_sourcesChanged[index].fire({});
notifySourcesChanged(list);
}
};
const auto i = _all.find(id.peer);
@ -751,7 +777,7 @@ void Stories::applyDeletedFromSources(PeerId id, StorySourcesList list) {
if (i != end(sources)) {
sources.erase(i);
}
_sourcesChanged[static_cast<int>(list)].fire({});
notifySourcesChanged(list);
}
void Stories::removeDependencyStory(not_null<Story*> story) {
@ -780,7 +806,7 @@ void Stories::sort(StorySourcesList list) {
return std::make_pair(key, info.id);
};
ranges::sort(sources, ranges::greater(), proj);
_sourcesChanged[index].fire({});
notifySourcesChanged(list);
preloadSourcesChanged(list);
}
@ -1044,7 +1070,7 @@ void Stories::toggleHidden(
const auto i = ranges::find(_sources[main], peerId, proj);
if (i != end(_sources[main])) {
_sources[main].erase(i);
_sourcesChanged[main].fire({});
notifySourcesChanged(StorySourcesList::NotHidden);
preloadSourcesChanged(StorySourcesList::NotHidden);
}
const auto j = ranges::find(_sources[other], peerId, proj);
@ -1058,7 +1084,7 @@ void Stories::toggleHidden(
const auto i = ranges::find(_sources[other], peerId, proj);
if (i != end(_sources[other])) {
_sources[other].erase(i);
_sourcesChanged[other].fire({});
notifySourcesChanged(StorySourcesList::Hidden);
preloadSourcesChanged(StorySourcesList::Hidden);
}
const auto j = ranges::find(_sources[main], peerId, proj);

View File

@ -24,6 +24,7 @@ enum class ReportReason;
namespace Data {
class Folder;
class Session;
struct StoryView;
struct StoryIdDates;
@ -282,6 +283,9 @@ private:
void preloadFinished(FullStoryId id, bool markAsPreloaded = false);
void preloadListsMore();
void notifySourcesChanged(StorySourcesList list);
void pushHiddenCountsToFolder();
[[nodiscard]] int pollingInterval(
const PollingSettings &settings) const;
void maybeSchedulePolling(
@ -319,6 +323,7 @@ private:
rpl::event_stream<> _sourcesChanged[kStorySourcesListCount];
bool _sourcesLoaded[kStorySourcesListCount] = { false };
QString _sourcesStates[kStorySourcesListCount];
Folder *_folderForHidden = nullptr;
mtpRequestId _loadMoreRequestId[kStorySourcesListCount] = { 0 };

View File

@ -257,7 +257,7 @@ dialogsFilter: InputField(defaultInputField) {
placeholderFg: placeholderFg;
placeholderFgActive: placeholderFgActive;
placeholderFgError: placeholderFgActive;
placeholderMargins: margins(2px, 0px, 2px, 0px);
placeholderMargins: margins(5px, 0px, 2px, 0px);
placeholderScale: 0.;
placeholderShift: -50px;
placeholderFont: normalFont;

View File

@ -233,20 +233,11 @@ void BasicRow::paintRipple(
void BasicRow::paintUserpic(
Painter &p,
not_null<PeerData*> peer,
not_null<Entry*> entry,
PeerData *peer,
Ui::VideoUserpic *videoUserpic,
History *historyForCornerBadge,
const Ui::PaintContext &context) const {
PaintUserpic(
p,
peer,
videoUserpic,
_userpic,
context.st->padding.left(),
context.st->padding.top(),
context.width,
context.st->photoSize,
context.paused);
PaintUserpic(p, entry, peer, videoUserpic, _userpic, context);
}
Row::Row(Key key, int index, int top) : _id(key), _top(top), _index(index) {
@ -334,7 +325,8 @@ void Row::ensureCornerBadgeUserpic() const {
void Row::PaintCornerBadgeFrame(
not_null<CornerBadgeUserpic*> data,
int framePadding,
not_null<PeerData*> peer,
not_null<Entry*> entry,
PeerData *peer,
Ui::VideoUserpic *videoUserpic,
Ui::PeerUserpicView &view,
const Ui::PaintContext &context) {
@ -356,16 +348,15 @@ void Row::PaintCornerBadgeFrame(
q.scale(scale, scale);
q.translate(-center, -center);
}
q.translate(-context.st->padding.left(), -context.st->padding.top());
PaintUserpic(
q,
entry,
peer,
videoUserpic,
view,
0,
0,
data->frame.width() / data->frame.devicePixelRatio(),
photoSize,
context.paused);
context);
q.translate(context.st->padding.left(), context.st->padding.top());
if (storiesCount) {
q.restore();
@ -401,7 +392,7 @@ void Row::PaintCornerBadgeFrame(
const auto &manager = data->layersManager;
if (const auto p = manager.progressForLayer(kBottomLayer); p > 0.) {
const auto size = photoSize;
if (data->cacheTTL.isNull() && peer->messagesTTL()) {
if (data->cacheTTL.isNull() && peer && peer->messagesTTL()) {
data->cacheTTL = CornerBadgeTTL(peer, view, size);
}
q.setOpacity(p);
@ -419,11 +410,12 @@ void Row::PaintCornerBadgeFrame(
}
q.setCompositionMode(QPainter::CompositionMode_Source);
const auto size = peer->isUser()
const auto online = peer && peer->isUser();
const auto size = online
? st::dialogsOnlineBadgeSize
: st::dialogsCallBadgeSize;
const auto stroke = st::dialogsOnlineBadgeStroke;
const auto skip = peer->isUser()
const auto skip = online
? st::dialogsOnlineBadgeSkip
: st::dialogsCallBadgeSkip;
const auto shrink = (size / 2) * (1. - topLayerProgress);
@ -444,27 +436,27 @@ void Row::PaintCornerBadgeFrame(
void Row::paintUserpic(
Painter &p,
not_null<PeerData*> peer,
not_null<Entry*> entry,
PeerData *peer,
Ui::VideoUserpic *videoUserpic,
History *historyForCornerBadge,
const Ui::PaintContext &context) const {
updateCornerBadgeShown(peer);
if (peer) {
updateCornerBadgeShown(peer);
}
const auto cornerBadgeShown = !_cornerBadgeUserpic
? _cornerBadgeShown
: !_cornerBadgeUserpic->layersManager.isDisplayedNone();
const auto storiesUser = historyForCornerBadge
? historyForCornerBadge->peer->asUser()
: nullptr;
const auto storiesHas = storiesUser && storiesUser->hasActiveStories();
if (!historyForCornerBadge || (!cornerBadgeShown && !storiesHas)) {
BasicRow::paintUserpic(
p,
peer,
videoUserpic,
historyForCornerBadge,
context);
if (!historyForCornerBadge || !_cornerBadgeShown) {
const auto storiesUser = peer ? peer->asUser() : nullptr;
const auto storiesFolder = peer ? nullptr : _id.folder();
const auto storiesHas = storiesUser
? storiesUser->hasActiveStories()
: storiesFolder
? storiesFolder->storiesCount()
: false;
if (!cornerBadgeShown && !storiesHas) {
BasicRow::paintUserpic(p, entry, peer, videoUserpic, context);
if (!peer || !_cornerBadgeShown) {
_cornerBadgeUserpic = nullptr;
}
return;
@ -478,20 +470,24 @@ void Row::paintUserpic(
const auto frameSide = (2 * framePadding + context.st->photoSize)
* ratio;
const auto frameSize = QSize(frameSide, frameSide);
const auto storiesSource = storiesHas
const auto storiesSource = (storiesHas && storiesUser)
? storiesUser->owner().stories().source(storiesUser->id)
: nullptr;
const auto storiesCountReal = storiesSource
? int(storiesSource->ids.size())
: storiesFolder
? storiesFolder->storiesCount()
: storiesHas
? 1
: 0;
const auto storiesUnreadCountReal = storiesSource
? storiesSource->unreadCount()
: (storiesHas && storiesUser->hasUnreadStories())
: storiesFolder
? storiesFolder->storiesUnreadCount()
: (storiesUser && storiesUser->hasUnreadStories())
? 1
: 0;
const auto limit = (1 << 7) - 1;
const auto limit = Ui::kOutlineSegmentsMax;
const auto storiesCount = std::min(storiesCountReal, limit);
const auto storiesUnreadCount = std::min(storiesUnreadCountReal, limit);
if (_cornerBadgeUserpic->frame.size() != frameSize) {
@ -500,8 +496,8 @@ void Row::paintUserpic(
QImage::Format_ARGB32_Premultiplied);
_cornerBadgeUserpic->frame.setDevicePixelRatio(ratio);
}
auto key = peer->userpicUniqueKey(userpicView());
key.first += peer->messagesTTL();
auto key = peer ? peer->userpicUniqueKey(userpicView()) : InMemoryKey();
key.first += peer ? peer->messagesTTL() : 0;
const auto frameIndex = videoUserpic ? videoUserpic->frameIndex() : -1;
const auto paletteVersionReal = style::PaletteVersion();
const auto paletteVersion = (paletteVersionReal & ((1 << 17) - 1));
@ -528,6 +524,7 @@ void Row::paintUserpic(
PaintCornerBadgeFrame(
_cornerBadgeUserpic.get(),
framePadding,
_id.entry(),
peer,
videoUserpic,
userpicView(),
@ -537,10 +534,11 @@ void Row::paintUserpic(
context.st->padding.left() - framePadding,
context.st->padding.top() - framePadding,
_cornerBadgeUserpic->frame);
if (historyForCornerBadge->peer->isUser()) {
const auto history = _id.history();
if (!history || history->peer->isUser()) {
return;
}
const auto actionPainter = historyForCornerBadge->sendActionPainter();
const auto actionPainter = history->sendActionPainter();
const auto bg = context.active
? st::dialogsBgActive
: st::dialogsBg;

View File

@ -35,6 +35,7 @@ struct TopicJumpCache;
namespace Dialogs {
class Entry;
enum class SortMode;
[[nodiscard]] QRect CornerBadgeTTLRect(int photoSize);
@ -46,9 +47,9 @@ public:
virtual void paintUserpic(
Painter &p,
not_null<PeerData*> peer,
not_null<Entry*> entry,
PeerData *peer,
Ui::VideoUserpic *videoUserpic,
History *historyForCornerBadge,
const Ui::PaintContext &context) const;
void addRipple(QPoint origin, QSize size, Fn<void()> updateCallback);
@ -99,9 +100,9 @@ public:
Fn<void()> updateCallback = nullptr) const;
void paintUserpic(
Painter &p,
not_null<PeerData*> peer,
not_null<Entry*> entry,
PeerData *peer,
Ui::VideoUserpic *videoUserpic,
History *historyForCornerBadge,
const Ui::PaintContext &context) const final override;
[[nodiscard]] bool lookupIsInTopicJump(int x, int y) const;
@ -183,7 +184,8 @@ private:
static void PaintCornerBadgeFrame(
not_null<CornerBadgeUserpic*> data,
int framePadding,
not_null<PeerData*> peer,
not_null<Entry*> entry,
PeerData *peer,
Ui::VideoUserpic *videoUserpic,
Ui::PeerUserpicView &view,
const Ui::PaintContext &context);

View File

@ -1419,6 +1419,7 @@ void Widget::updateStoriesVisibility() {
if (_scroll->position().overscroll < 0) {
_scroll->scrollToY(0);
}
_scroll->update();
} else {
_scroll->setOverscrollDefaults(0, 0);
_scroll->setOverscrollTypes(Type::Virtual, Type::Real);

View File

@ -331,22 +331,23 @@ void PaintRow(
context.st->padding.top(),
context.width,
context.st->photoSize);
} else if (from) {
row->paintUserpic(
p,
from,
videoUserpic,
(flags & Flag::AllowUserOnline) ? history : nullptr,
context);
} else if (hiddenSenderInfo) {
} else if (!from && hiddenSenderInfo) {
hiddenSenderInfo->emptyUserpic.paintCircle(
p,
context.st->padding.left(),
context.st->padding.top(),
context.width,
context.st->photoSize);
} else if (!(flags & Flag::AllowUserOnline)) {
PaintUserpic(
p,
entry,
from,
videoUserpic,
row->userpicView(),
context);
} else {
entry->paintUserpic(p, row->userpicView(), context);
row->paintUserpic(p, entry, from, videoUserpic, context);
}
auto nameleft = context.st->nameLeft;
@ -785,7 +786,7 @@ void RowPainter::Paint(
? history->peer->migrateTo()
: history->peer.get())
: nullptr;
const auto allowUserOnline = !context.narrow || badgesState.empty();
const auto allowUserOnline = true;// !context.narrow || badgesState.empty();
const auto flags = (allowUserOnline ? Flag::AllowUserOnline : Flag(0))
| (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0))
| (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0))

View File

@ -7,13 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "dialogs/ui/dialogs_video_userpic.h"
#include "ui/painter.h"
#include "core/file_location.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_file_origin.h"
#include "data/data_session.h"
#include "dialogs/ui/dialogs_layout.h"
#include "ui/painter.h"
#include "styles/style_dialogs.h"
namespace Dialogs::Ui {
@ -129,6 +131,29 @@ void VideoUserpic::clipCallback(Media::Clip::Notification notification) {
}
}
void PaintUserpic(
Painter &p,
not_null<Entry*> entry,
PeerData *peer,
VideoUserpic *videoUserpic,
PeerUserpicView &view,
const Ui::PaintContext &context) {
if (peer) {
PaintUserpic(
p,
peer,
videoUserpic,
view,
context.st->padding.left(),
context.st->padding.top(),
context.width,
context.st->photoSize,
context.paused);
} else {
entry->paintUserpic(p, view, context);
}
}
void PaintUserpic(
Painter &p,
not_null<PeerData*> peer,

View File

@ -19,10 +19,16 @@ namespace Ui {
struct PeerUserpicView;
} // namespace Ui
namespace Dialogs {
class Entry;
} // namespace Dialogs
namespace Dialogs::Ui {
using namespace ::Ui;
struct PaintContext;
class VideoUserpic final {
public:
VideoUserpic(not_null<PeerData*> peer, Fn<void()> repaint);
@ -54,6 +60,14 @@ private:
};
void PaintUserpic(
Painter &p,
not_null<Entry*> entry,
PeerData *peer,
VideoUserpic *videoUserpic,
PeerUserpicView &view,
const Ui::PaintContext &context);
void PaintUserpic(
Painter &p,
not_null<PeerData*> peer,

View File

@ -17,7 +17,7 @@ void PaintOutlineSegments(
Expects(!segments.empty());
p.setBrush(Qt::NoBrush);
const auto count = int(segments.size());
const auto count = std::min(int(segments.size()), kOutlineSegmentsMax);
if (count == 1) {
p.setPen(QPen(segments.front().brush, segments.front().width));
p.drawEllipse(ellipse);

View File

@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui {
inline constexpr auto kOutlineSegmentsMax = 50;
struct OutlineSegment {
QBrush brush;
float64 width = 0.;

View File

@ -572,7 +572,7 @@ void MainMenu::setupArchive() {
const auto checkArchive = [=] {
const auto f = folder();
return f
&& !f->chatsList()->empty()
&& (!f->chatsList()->empty() || f->storiesCount() > 0)
&& controller->session().settings().archiveInMainMenu();
};
@ -650,10 +650,15 @@ void MainMenu::setupArchive() {
return Badge::UnreadBadge{ state.unreadCounter, true };
}));
controller->session().data().chatsListChanges(
) | rpl::filter([](Data::Folder *folder) {
return folder && (folder->id() == Data::Folder::kId);
}) | rpl::start_with_next([=] {
rpl::merge(
controller->session().data().chatsListChanges(
) | rpl::filter([](Data::Folder *folder) {
return folder && (folder->id() == Data::Folder::kId);
}) | rpl::to_empty,
controller->session().data().stories().sourcesChanged(
Data::StorySourcesList::Hidden
)
) | rpl::start_with_next([=] {
const auto isArchiveVisible = checkArchive();
wrap->toggle(isArchiveVisible, anim::type::normal);
if (!isArchiveVisible) {

View File

@ -949,7 +949,8 @@ SessionController::SessionController(
) | rpl::filter([=](Data::Folder *folder) {
return (folder != nullptr)
&& (folder == _openedFolder.current())
&& folder->chatsList()->indexed()->empty();
&& folder->chatsList()->indexed()->empty()
&& !folder->storiesCount();
}) | rpl::start_with_next([=](Data::Folder *folder) {
folder->updateChatListSortPosition();
closeFolder();

@ -1 +1 @@
Subproject commit c7e0b7af37bce7ec77195ff717d70457e51e1e7a
Subproject commit 1c0889f78a74bb29e8cea6986ea8b18e7add7fb0