mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 07:07:08 +02:00
Update story mention layout, add outline.
Also use uint32 for bool-bitfields, otherwise: int a : 1 = 0; ... const auto test = true; const auto b = test ? 1 : 0; if (a != b) { a = b; ... } Assert(a == b); // Violation, because a == -1, not 1 (after a = b).
This commit is contained in:
parent
d7d8847c1d
commit
a0ffa15885
15 changed files with 151 additions and 52 deletions
Telegram/SourceFiles
|
@ -163,7 +163,7 @@ StoriesRow::StoriesRow(
|
|||
void StoriesRow::applySegments(const Dialogs::Stories::Element &element) {
|
||||
Expects(element.unreadCount <= element.count);
|
||||
|
||||
_count = std::max(element.count, 1);
|
||||
_count = int(std::max(element.count, 1U));
|
||||
_unreadCount = element.unreadCount;
|
||||
refreshSegments();
|
||||
}
|
||||
|
|
|
@ -75,9 +75,9 @@ StoriesSourceInfo StoriesSource::info() const {
|
|||
return {
|
||||
.id = user->id,
|
||||
.last = ids.empty() ? 0 : ids.back().date,
|
||||
.count = std::min(int(ids.size()), kMaxSegmentsCount),
|
||||
.unreadCount = std::min(unreadCount(), kMaxSegmentsCount),
|
||||
.premium = user->isPremium() ? 1 : 0,
|
||||
.count = uint32(std::min(int(ids.size()), kMaxSegmentsCount)),
|
||||
.unreadCount = uint32(std::min(unreadCount(), kMaxSegmentsCount)),
|
||||
.premium = user->isPremium() ? 1U : 0U,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -913,9 +913,25 @@ void Stories::markAsRead(FullStoryId id, bool viewed) {
|
|||
|
||||
bool Stories::bumpReadTill(PeerId peerId, StoryId maxReadTill) {
|
||||
auto &till = _readTill[peerId];
|
||||
auto refreshItems = std::vector<StoryId>();
|
||||
const auto guard = gsl::finally([&] {
|
||||
for (const auto id : refreshItems) {
|
||||
_owner->refreshStoryItemViews({ peerId, id });
|
||||
}
|
||||
});
|
||||
if (till < maxReadTill) {
|
||||
const auto from = till;
|
||||
till = maxReadTill;
|
||||
updateUserStoriesState(_owner->peer(peerId));
|
||||
const auto i = _stories.find(peerId);
|
||||
if (i != end(_stories)) {
|
||||
refreshItems = ranges::make_subrange(
|
||||
i->second.lower_bound(from + 1),
|
||||
i->second.lower_bound(till + 1)
|
||||
) | ranges::views::transform([](const auto &pair) {
|
||||
return pair.first;
|
||||
}) | ranges::to_vector;
|
||||
}
|
||||
}
|
||||
const auto i = _all.find(peerId);
|
||||
if (i == end(_all) || i->second.readTill >= maxReadTill) {
|
||||
|
@ -1443,21 +1459,40 @@ std::optional<Stories::PeerSourceState> Stories::peerSourceState(
|
|||
(i != end(_readTill)) ? i->second : 0),
|
||||
};
|
||||
}
|
||||
if (!_readTillsRequestId) {
|
||||
const auto api = &_owner->session().api();
|
||||
_readTillsRequestId = api->request(MTPstories_GetAllReadUserStories(
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_readTillReceived = true;
|
||||
api->applyUpdates(result);
|
||||
for (auto &[peer, maxId] : base::take(_pendingUserStateMaxId)) {
|
||||
updateUserStoriesState(peer);
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
requestReadTills();
|
||||
_pendingUserStateMaxId[peer] = storyMaxId;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Stories::requestReadTills() {
|
||||
if (_readTillReceived || _readTillsRequestId) {
|
||||
return;
|
||||
}
|
||||
const auto api = &_owner->session().api();
|
||||
_readTillsRequestId = api->request(MTPstories_GetAllReadUserStories(
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_readTillReceived = true;
|
||||
api->applyUpdates(result);
|
||||
for (auto &[peer, maxId] : base::take(_pendingUserStateMaxId)) {
|
||||
updateUserStoriesState(peer);
|
||||
}
|
||||
for (const auto &storyId : base::take(_pendingReadTillItems)) {
|
||||
_owner->refreshStoryItemViews(storyId);
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
bool Stories::isUnread(not_null<Story*> story) {
|
||||
const auto till = _readTill.find(story->peer()->id);
|
||||
if (till == end(_readTill) && !_readTillReceived) {
|
||||
requestReadTills();
|
||||
_pendingReadTillItems.emplace(story->fullId());
|
||||
return false;
|
||||
}
|
||||
const auto readTill = (till != end(_readTill)) ? till->second : 0;
|
||||
return (story->id() > readTill);
|
||||
}
|
||||
|
||||
void Stories::updateUserStoriesState(not_null<PeerData*> peer) {
|
||||
const auto till = _readTill.find(peer->id);
|
||||
const auto readTill = (till != end(_readTill)) ? till->second : 0;
|
||||
|
|
|
@ -41,9 +41,9 @@ struct StoriesIds {
|
|||
struct StoriesSourceInfo {
|
||||
PeerId id = 0;
|
||||
TimeId last = 0;
|
||||
int count : 15 = 0;
|
||||
int unreadCount : 15 = 0;
|
||||
int premium : 1 = 0;
|
||||
uint32 count : 15 = 0;
|
||||
uint32 unreadCount : 15 = 0;
|
||||
uint32 premium : 1 = 0;
|
||||
|
||||
friend inline bool operator==(
|
||||
StoriesSourceInfo,
|
||||
|
@ -207,6 +207,7 @@ public:
|
|||
[[nodiscard]] std::optional<PeerSourceState> peerSourceState(
|
||||
not_null<PeerData*> peer,
|
||||
StoryId storyMaxId);
|
||||
[[nodiscard]] bool isUnread(not_null<Story*> story);
|
||||
|
||||
private:
|
||||
struct Saved {
|
||||
|
@ -241,6 +242,7 @@ private:
|
|||
void savedStateUpdated(not_null<Story*> story);
|
||||
void sort(StorySourcesList list);
|
||||
bool bumpReadTill(PeerId peerId, StoryId maxReadTill);
|
||||
void requestReadTills();
|
||||
|
||||
[[nodiscard]] std::shared_ptr<HistoryItem> lookupItem(
|
||||
not_null<Story*> story);
|
||||
|
@ -329,6 +331,7 @@ private:
|
|||
int _preloadingMainSourcesCounter = 0;
|
||||
|
||||
base::flat_map<PeerId, StoryId> _readTill;
|
||||
base::flat_set<FullStoryId> _pendingReadTillItems;
|
||||
base::flat_map<not_null<PeerData*>, StoryId> _pendingUserStateMaxId;
|
||||
mtpRequestId _readTillsRequestId = 0;
|
||||
bool _readTillReceived = false;
|
||||
|
|
|
@ -367,6 +367,9 @@ void Row::PaintCornerBadgeFrame(
|
|||
|
||||
const auto st = context.st;
|
||||
const auto storiesUnreadBrush = [&] {
|
||||
if (context.active) {
|
||||
return st::dialogsUnreadBgActive->b;
|
||||
}
|
||||
const auto left = st->padding.left();
|
||||
const auto top = st->padding.top();
|
||||
auto gradient = QLinearGradient(
|
||||
|
|
|
@ -170,10 +170,10 @@ private:
|
|||
QImage frame;
|
||||
QImage cacheTTL;
|
||||
int frameIndex = -1;
|
||||
int paletteVersion : 24 = 0;
|
||||
int storiesShown : 1 = 0;
|
||||
int storiesUnread : 1 = 0;
|
||||
int active : 1 = 0;
|
||||
uint32 paletteVersion : 24 = 0;
|
||||
uint32 storiesShown : 1 = 0;
|
||||
uint32 storiesUnread : 1 = 0;
|
||||
uint32 active : 1 = 0;
|
||||
};
|
||||
|
||||
void setCornerBadgeShown(
|
||||
|
@ -192,9 +192,9 @@ private:
|
|||
mutable std::unique_ptr<CornerBadgeUserpic> _cornerBadgeUserpic;
|
||||
int _top = 0;
|
||||
int _height = 0;
|
||||
int _index : 30 = 0;
|
||||
int _cornerBadgeShown : 1 = 0;
|
||||
int _topicJumpRipple : 1 = 0;
|
||||
uint32 _index : 30 = 0;
|
||||
uint32 _cornerBadgeShown : 1 = 0;
|
||||
uint32 _topicJumpRipple : 1 = 0;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -353,7 +353,7 @@ Content State::next() {
|
|||
.thumbnail = std::move(userpic),
|
||||
.count = info.count,
|
||||
.unreadCount = info.unreadCount,
|
||||
.skipSmall = user->isSelf() ? 1 : 0,
|
||||
.skipSmall = user->isSelf() ? 1U : 0U,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
|
@ -424,8 +424,8 @@ rpl::producer<Content> LastForPeer(not_null<PeerData*> peer) {
|
|||
result.elements.push_back({
|
||||
.id = uint64(id),
|
||||
.thumbnail = MakeStoryThumbnail(*maybe),
|
||||
.count = 1,
|
||||
.unreadCount = (id > readTill) ? 1 : 0,
|
||||
.count = 1U,
|
||||
.unreadCount = (id > readTill) ? 1U : 0U,
|
||||
});
|
||||
}
|
||||
} else if (maybe.error() == Data::NoStory::Unknown) {
|
||||
|
|
|
@ -36,9 +36,9 @@ struct Element {
|
|||
uint64 id = 0;
|
||||
QString name;
|
||||
std::shared_ptr<Thumbnail> thumbnail;
|
||||
int count : 15 = 0;
|
||||
int unreadCount : 15 = 0;
|
||||
int skipSmall : 1 = 0;
|
||||
uint32 count : 15 = 0;
|
||||
uint32 unreadCount : 15 = 0;
|
||||
uint32 skipSmall : 1 = 0;
|
||||
|
||||
friend inline bool operator==(
|
||||
const Element &a,
|
||||
|
|
|
@ -164,7 +164,7 @@ void Photo::unloadHeavyPart() {
|
|||
|
||||
QSize Photo::countOptimalSize() {
|
||||
if (_serviceWidth > 0) {
|
||||
return { _serviceWidth, _serviceWidth };
|
||||
return { int(_serviceWidth), int(_serviceWidth) };
|
||||
}
|
||||
|
||||
if (_parent->media() != this) {
|
||||
|
@ -209,7 +209,7 @@ QSize Photo::countOptimalSize() {
|
|||
|
||||
QSize Photo::countCurrentSize(int newWidth) {
|
||||
if (_serviceWidth) {
|
||||
return { _serviceWidth, _serviceWidth };
|
||||
return { int(_serviceWidth), int(_serviceWidth) };
|
||||
}
|
||||
const auto thumbMaxWidth = qMin(newWidth, st::maxMediaSize);
|
||||
const auto minWidth = std::clamp(
|
||||
|
|
|
@ -167,10 +167,10 @@ private:
|
|||
const std::unique_ptr<MediaSpoiler> _spoiler;
|
||||
mutable QImage _imageCache;
|
||||
mutable std::optional<Ui::BubbleRounding> _imageCacheRounding;
|
||||
int _serviceWidth : 29 = 0;
|
||||
mutable int _imageCacheForum : 1 = 0;
|
||||
mutable int _imageCacheBlurred : 1 = 0;
|
||||
mutable int _story : 1 = 0;
|
||||
uint32 _serviceWidth : 29 = 0;
|
||||
mutable uint32 _imageCacheForum : 1 = 0;
|
||||
mutable uint32 _imageCacheBlurred : 1 = 0;
|
||||
mutable uint32 _story : 1 = 0;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -81,8 +81,7 @@ ServiceBox::ServiceBox(
|
|||
+ _subtitle.countHeight(_maxWidth)
|
||||
+ (_button.empty()
|
||||
? 0
|
||||
: (st::msgServiceGiftBoxButtonMargins.top()
|
||||
+ _button.size.height()))
|
||||
: (_content->buttonSkip() + _button.size.height()))
|
||||
+ st::msgServiceGiftBoxButtonMargins.bottom()))
|
||||
, _innerSize(_size - QSize(0, st::msgServiceGiftBoxTopSkip)) {
|
||||
}
|
||||
|
@ -165,6 +164,11 @@ TextState ServiceBox::textState(QPoint point, StateRequest request) const {
|
|||
if (rect.contains(point)) {
|
||||
result.link = _button.link;
|
||||
_button.lastPoint = point - rect.topLeft();
|
||||
} else if (contentRect().contains(point)) {
|
||||
if (!_contentLink) {
|
||||
_contentLink = _content->createViewLink();
|
||||
}
|
||||
result.link = _contentLink;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -23,6 +23,9 @@ public:
|
|||
[[nodiscard]] virtual QSize size() = 0;
|
||||
[[nodiscard]] virtual QString title() = 0;
|
||||
[[nodiscard]] virtual TextWithEntities subtitle() = 0;
|
||||
[[nodiscard]] virtual int buttonSkip() {
|
||||
return top();
|
||||
}
|
||||
[[nodiscard]] virtual QString button() = 0;
|
||||
virtual void draw(
|
||||
Painter &p,
|
||||
|
@ -84,6 +87,7 @@ private:
|
|||
|
||||
const not_null<Element*> _parent;
|
||||
const std::unique_ptr<ServiceBoxContent> _content;
|
||||
mutable ClickHandlerPtr _contentLink;
|
||||
|
||||
struct Button {
|
||||
void drawBg(QPainter &p) const;
|
||||
|
|
|
@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "main/main_session.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/painter.h"
|
||||
|
@ -39,13 +40,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
constexpr auto kReadOutlineAlpha = 0.5;
|
||||
|
||||
} // namespace
|
||||
|
||||
StoryMention::StoryMention(
|
||||
not_null<Element*> parent,
|
||||
not_null<Data::Story*> story)
|
||||
: _parent(parent)
|
||||
, _story(story) {
|
||||
, _story(story)
|
||||
, _unread(story->owner().stories().isUnread(story) ? 1 : 0) {
|
||||
}
|
||||
|
||||
StoryMention::~StoryMention() = default;
|
||||
|
@ -62,6 +66,10 @@ QString StoryMention::title() {
|
|||
return QString();
|
||||
}
|
||||
|
||||
int StoryMention::buttonSkip() {
|
||||
return st::storyMentionButtonSkip;
|
||||
}
|
||||
|
||||
QString StoryMention::button() {
|
||||
return tr::lng_action_story_mention_button(tr::now);
|
||||
}
|
||||
|
@ -86,7 +94,7 @@ void StoryMention::draw(
|
|||
Painter &p,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry) {
|
||||
const auto showStory = !_story->forbidsForward();
|
||||
const auto showStory = _story->forbidsForward() ? 0 : 1;
|
||||
if (!_thumbnail || _thumbnailFromStory != showStory) {
|
||||
using namespace Dialogs::Stories;
|
||||
const auto item = _parent->data();
|
||||
|
@ -97,18 +105,49 @@ void StoryMention::draw(
|
|||
? history->session().user()
|
||||
: history->peer);
|
||||
_thumbnailFromStory = showStory;
|
||||
_subscribed = false;
|
||||
_subscribed = 0;
|
||||
}
|
||||
if (!_subscribed) {
|
||||
_thumbnail->subscribeToUpdates([=] {
|
||||
_parent->data()->history()->owner().requestViewRepaint(_parent);
|
||||
});
|
||||
_subscribed = true;
|
||||
_subscribed = 1;
|
||||
}
|
||||
|
||||
const auto padding = (geometry.width() - st::storyMentionSize) / 2;
|
||||
const auto size = geometry.width() - 2 * padding;
|
||||
p.drawImage(
|
||||
geometry.topLeft(),
|
||||
_thumbnail->image(st::msgServicePhotoWidth));
|
||||
geometry.topLeft() + QPoint(padding, padding),
|
||||
_thumbnail->image(size));
|
||||
|
||||
const auto thumbnail = geometry.marginsRemoved(
|
||||
QMargins(padding, padding, padding, padding));
|
||||
const auto added = 0.5 * (_unread
|
||||
? st::storyMentionUnreadSkipTwice
|
||||
: st::storyMentionReadSkipTwice);
|
||||
const auto outline = thumbnail.marginsAdded(
|
||||
QMargins(added, added, added, added));
|
||||
if (_unread && _paletteVersion != style::PaletteVersion()) {
|
||||
_paletteVersion = style::PaletteVersion();
|
||||
auto gradient = QLinearGradient(
|
||||
outline.topRight(),
|
||||
outline.bottomLeft());
|
||||
gradient.setStops({
|
||||
{ 0., st::groupCallLive1->c },
|
||||
{ 1., st::groupCallMuted1->c },
|
||||
});
|
||||
_unreadBrush = QBrush(gradient);
|
||||
}
|
||||
auto readColor = context.st->msgServiceFg()->c;
|
||||
readColor.setAlphaF(std::min(readColor.alphaF(), kReadOutlineAlpha));
|
||||
p.setPen(QPen(
|
||||
_unread ? _unreadBrush : QBrush(readColor),
|
||||
0.5 * (_unread
|
||||
? st::storyMentionUnreadStrokeTwice
|
||||
: st::storyMentionReadStrokeTwice)));
|
||||
p.setBrush(Qt::NoBrush);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.drawEllipse(outline);
|
||||
}
|
||||
|
||||
void StoryMention::stickerClearLoopPlayed() {
|
||||
|
@ -121,12 +160,12 @@ std::unique_ptr<StickerPlayer> StoryMention::stickerTakePlayer(
|
|||
}
|
||||
|
||||
bool StoryMention::hasHeavyPart() {
|
||||
return _subscribed;
|
||||
return _subscribed != 0;
|
||||
}
|
||||
|
||||
void StoryMention::unloadHeavyPart() {
|
||||
if (_subscribed) {
|
||||
_subscribed = false;
|
||||
_subscribed = 0;
|
||||
_thumbnail->subscribeToUpdates(nullptr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
QSize size() override;
|
||||
QString title() override;
|
||||
TextWithEntities subtitle() override;
|
||||
int buttonSkip() override;
|
||||
QString button() override;
|
||||
void draw(
|
||||
Painter &p,
|
||||
|
@ -57,8 +58,11 @@ private:
|
|||
const not_null<Element*> _parent;
|
||||
const not_null<Data::Story*> _story;
|
||||
std::shared_ptr<Thumbnail> _thumbnail;
|
||||
bool _thumbnailFromStory = false;
|
||||
bool _subscribed = false;
|
||||
QBrush _unreadBrush;
|
||||
uint32 _paletteVersion : 29 = 0;
|
||||
uint32 _thumbnailFromStory : 1 = 0;
|
||||
uint32 _subscribed : 1 = 0;
|
||||
uint32 _unread : 1 = 0;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -841,7 +841,7 @@ searchInChatPeerList: PeerList(defaultPeerList) {
|
|||
}
|
||||
|
||||
msgServiceGiftBoxSize: size(206px, 231px); // Plus msgServiceGiftBoxTopSkip.
|
||||
msgServiceGiftBoxRadius: 12px;
|
||||
msgServiceGiftBoxRadius: 20px;
|
||||
msgServiceGiftBoxTopSkip: 4px;
|
||||
msgServiceGiftBoxButtonHeight: 32px;
|
||||
msgServiceGiftBoxButtonPadding: margins(2px, 0px, 2px, 0px);
|
||||
|
@ -915,3 +915,10 @@ backgroundSwitchToLight: IconButton(backgroundSwitchToDark) {
|
|||
icon: icon {{ "menu/header_mode_day", boxTitleCloseFg }};
|
||||
iconOver: icon {{ "menu/header_mode_day", boxTitleCloseFgOver }};
|
||||
}
|
||||
|
||||
storyMentionSize: 80px;
|
||||
storyMentionUnreadSkipTwice: 8px;
|
||||
storyMentionUnreadStrokeTwice: 6px;
|
||||
storyMentionReadSkipTwice: 7px;
|
||||
storyMentionReadStrokeTwice: 3px;
|
||||
storyMentionButtonSkip: 5px;
|
||||
|
|
|
@ -25,8 +25,8 @@ struct PeerUserpicView {
|
|||
QImage cached;
|
||||
std::shared_ptr<QImage> cloud;
|
||||
base::weak_ptr<const EmptyUserpic> empty;
|
||||
int paletteVersion : 31 = 0;
|
||||
int forum : 1 = 0;
|
||||
uint32 paletteVersion : 31 = 0;
|
||||
uint32 forum : 1 = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool PeerUserpicLoading(const PeerUserpicView &view);
|
||||
|
|
Loading…
Add table
Reference in a new issue