2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-22 02:07:24 +00:00

Display hidden state in story albums.

This commit is contained in:
John Preston 2025-07-29 12:27:29 +04:00
parent 677891d0ff
commit 953487bb65
21 changed files with 247 additions and 103 deletions

11
.gitignore vendored
View File

@ -53,3 +53,14 @@ stage
*.*~
.idea/
cmake-build-debug/
# Local configuration files
settings.local.json
*.local.json
.env
.env.local
.env.*.local
# Cursor IDE local settings (but keep .cursor/rules/)
.cursor/*
!.cursor/rules/

View File

@ -1945,6 +1945,35 @@ void Stories::albumRename(
}).send();
}
void Stories::albumDelete(not_null<PeerData*> peer, int id) {
_owner->session().api().request(MTPstories_DeleteAlbum(
peer->input,
MTP_int(id)
)).send();
auto &albums = _albums[peer->id];
auto current = albums.list.current();
current.erase(
ranges::remove(current, id, &StoryAlbum::id),
end(current));
albums.list = std::move(current);
const auto i = albums.sets.find(id);
if (i != end(albums.sets)) {
_owner->session().api().request(
base::take(i->second.requestId)).cancel();
for (const auto storyId : i->second.albumKnownInArchive) {
if (const auto story = lookup({ peer->id, storyId })) {
auto now = (*story)->albumIds();
if (now.remove(id)) {
(*story)->setAlbumIds(std::move(now));
}
}
}
albums.sets.erase(i);
}
}
void Stories::notifyAlbumUpdate(StoryAlbumUpdate &&update) {
const auto peerId = update.peer->id;
const auto i = _albums.find(peerId);

View File

@ -235,6 +235,7 @@ public:
const QString &title,
Fn<void(StoryAlbum)> done,
Fn<void(QString)> fail);
void albumDelete(not_null<PeerData*> peer, int id);
void notifyAlbumUpdate(StoryAlbumUpdate &&update);
[[nodiscard]] rpl::producer<StoryAlbumUpdate> albumUpdates() const;

View File

@ -367,7 +367,12 @@ bool Story::pinnedToTop() const {
}
void Story::setInProfile(bool value) {
if (_inProfile != value) {
_inProfile = value;
if (const auto item = _peer->owner().stories().lookupItem(this)) {
item->setStoryInProfile(value);
}
}
}
bool Story::inProfile() const {

View File

@ -356,6 +356,8 @@ enum class MessageFlag : uint64 {
StarsPaidSuggested = (1ULL << 52),
TonPaidSuggested = (1ULL << 53),
StoryInProfile = (1ULL << 54),
};
inline constexpr bool is_flag_type(MessageFlag) { return true; }
using MessageFlags = base::flags<MessageFlag>;

View File

@ -1634,6 +1634,17 @@ void HistoryItem::setIsPinned(bool pinned) {
}
}
void HistoryItem::setStoryInProfile(bool inProfile) {
if (storyInProfile() == inProfile) {
return;
} else if (inProfile) {
_flags |= MessageFlag::StoryInProfile;
} else {
_flags &= ~MessageFlag::StoryInProfile;
}
_history->owner().notifyItemDataChange(this);
}
void HistoryItem::returnSavedMedia() {
if (!isEditingMedia()) {
return;
@ -2014,6 +2025,11 @@ void HistoryItem::setStoryFields(not_null<Data::Story*> story) {
} else {
_flags &= ~MessageFlag::Pinned;
}
if (story->inProfile()) {
_flags |= MessageFlag::StoryInProfile;
} else {
_flags &= ~MessageFlag::StoryInProfile;
}
}
void HistoryItem::applyEdition(const MTPDmessageService &message) {

View File

@ -235,6 +235,9 @@ public:
[[nodiscard]] bool invertMedia() const {
return _flags & MessageFlag::InvertMedia;
}
[[nodiscard]] bool storyInProfile() const {
return _flags & MessageFlag::StoryInProfile;
}
[[nodiscard]] bool unread(not_null<Data::Thread*> thread) const;
[[nodiscard]] bool showNotification() const;
void markClientSideAsRead();
@ -250,6 +253,7 @@ public:
void markMediaAndMentionRead();
bool markContentsRead(bool fromThisClient = false);
void setIsPinned(bool isPinned);
void setStoryInProfile(bool inProfile);
// For edit media in history_message.
void returnSavedMedia();

View File

@ -588,10 +588,6 @@ void TopBar::setStories(rpl::producer<Dialogs::Stories::Content> content) {
updateControlsVisibility(anim::type::instant);
}
void TopBar::setStoriesArchive(bool archive) {
_storiesArchive = archive;
}
void TopBar::setSelectedItems(SelectedItems &&items) {
auto wasSelectionMode = selectionMode();
_selectedItems = std::move(items);
@ -628,10 +624,19 @@ void TopBar::updateSelectionState() {
_canDelete = computeCanDelete();
_canForward = computeCanForward();
_canUnpinStories = computeCanUnpinStories();
_canToggleStoryPin = computeCanToggleStoryPin();
_allStoriesInProfile = computeAllStoriesInProfile();
_selectionText->entity()->setValue(generateSelectedText());
_delete->toggle(_canDelete, anim::type::instant);
_forward->toggle(_canForward, anim::type::instant);
_toggleStoryInProfile->toggle(_canToggleStoryPin, anim::type::instant);
_toggleStoryInProfile->entity()->setIconOverride(
(_allStoriesInProfile
? &_st.storiesArchive.icon
: &_st.storiesSave.icon),
(_allStoriesInProfile
? &_st.storiesArchive.iconOver
: &_st.storiesSave.iconOver));
_toggleStoryPin->toggle(_canToggleStoryPin, anim::type::instant);
_toggleStoryPin->entity()->setIconOverride(
_canUnpinStories ? &_st.storiesUnpin.icon : nullptr,
@ -652,6 +657,7 @@ void TopBar::createSelectionControls() {
_canForward = computeCanForward();
_canUnpinStories = computeCanUnpinStories();
_canToggleStoryPin = computeCanToggleStoryPin();
_allStoriesInProfile = computeAllStoriesInProfile();
_cancelSelection = wrap(Ui::CreateChild<Ui::FadeWrap<Ui::IconButton>>(
this,
object_ptr<Ui::IconButton>(this, _st.mediaCancel),
@ -710,16 +716,18 @@ void TopBar::createSelectionControls() {
this,
object_ptr<Ui::IconButton>(
this,
_storiesArchive ? _st.storiesSave : _st.storiesArchive),
_allStoriesInProfile ? _st.storiesArchive : _st.storiesSave),
st::infoTopBarScale));
registerToggleControlCallback(
_toggleStoryInProfile.data(),
[this] { return selectionMode() && _canToggleStoryPin; });
_toggleStoryInProfile->setDuration(st::infoTopBarDuration);
_toggleStoryInProfile->entity()->clicks(
) | rpl::map_to(
SelectionAction::ToggleStoryInProfile
) | rpl::start_to_stream(
) | rpl::map([=] {
return _allStoriesInProfile
? SelectionAction::ToggleStoryToArchive
: SelectionAction::ToggleStoryToProfile;
}) | rpl::start_to_stream(
_selectionActionRequests,
_cancelSelection->lifetime());
_toggleStoryInProfile->entity()->setVisible(_canToggleStoryPin);
@ -769,6 +777,12 @@ bool TopBar::computeCanToggleStoryPin() const {
&SelectedItem::canToggleStoryPin);
}
bool TopBar::computeAllStoriesInProfile() const {
return ranges::all_of(
_selectedItems.list,
&SelectedItem::storyInProfile);
}
Ui::StringWithNumbers TopBar::generateSelectedText() const {
return _selectedItems.title(_selectedItems.list.size());
}

View File

@ -63,7 +63,6 @@ public:
void setTitle(TitleDescriptor descriptor);
void setStories(rpl::producer<Dialogs::Stories::Content> content);
void setStoriesArchive(bool archive);
void enableBackButton();
void highlight();
@ -131,6 +130,7 @@ private:
[[nodiscard]] bool computeCanForward() const;
[[nodiscard]] bool computeCanUnpinStories() const;
[[nodiscard]] bool computeCanToggleStoryPin() const;
[[nodiscard]] bool computeAllStoriesInProfile() const;
void updateSelectionState();
void createSelectionControls();
@ -178,7 +178,7 @@ private:
bool _canForward = false;
bool _canToggleStoryPin = false;
bool _canUnpinStories = false;
bool _storiesArchive = false;
bool _allStoriesInProfile = false;
QPointer<Ui::FadeWrap<Ui::IconButton>> _cancelSelection;
QPointer<Ui::FadeWrap<Ui::LabelWithNumbers>> _selectionText;
QPointer<Ui::FadeWrap<Ui::IconButton>> _forward;

View File

@ -657,8 +657,6 @@ void WrapWidget::finishShowContent() {
.subtitle = _content->subtitle(),
});
_topBar->setStories(_content->titleStories());
_topBar->setStoriesArchive(
_controller->key().storiesAlbumId() == Stories::ArchiveId());
}
_desiredHeights.fire(desiredHeightForContent());
_desiredShadowVisibilities.fire(_content->desiredShadowVisibility());
@ -787,7 +785,6 @@ bool WrapWidget::showInternal(
&& (params.way == Window::SectionShow::Way::ClearStack);
if (_controller->validateMementoPeer(content)) {
if (!skipInternal && _content->showInternal(content)) {
highlightTopBar();
return true;
}
}

View File

@ -65,6 +65,7 @@ struct SelectedItem {
bool canForward = false;
bool canToggleStoryPin = false;
bool canUnpinStory = false;
bool storyInProfile = false;
};
struct SelectedItems {
@ -80,7 +81,8 @@ enum class SelectionAction {
Forward,
Delete,
ToggleStoryPin,
ToggleStoryInProfile,
ToggleStoryToProfile,
ToggleStoryToArchive,
};
class WrapWidget final : public Window::SectionWidget {

View File

@ -32,6 +32,7 @@ struct ListItemSelectionData {
bool canForward = false;
bool canToggleStoryPin = false;
bool canUnpinStory = false;
bool storyInProfile = false;
friend inline bool operator==(
ListItemSelectionData,

View File

@ -58,6 +58,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/player/media_player_instance.h"
#include "boxes/delete_messages_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/sticker_set_box.h" // StickerPremiumMark
#include "core/file_utilities.h"
#include "core/application.h"
#include "ui/toast/toast.h"
@ -66,6 +67,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_layers.h"
#include "styles/style_menu_icons.h"
#include "styles/style_chat.h"
#include "styles/style_credits.h" // giftBoxHiddenMark
#include <QtWidgets/QApplication>
#include <QtGui/QClipboard>
@ -152,7 +154,11 @@ ListWidget::ListWidget(
_provider->type(),
[=] { scrollDateCheck(); },
[=] { scrollDateHide(); }))
, _storiesAddToAlbumId(controller->storiesAddToAlbumId()) {
, _storiesAddToAlbumId(controller->storiesAddToAlbumId())
, _hiddenMark(std::make_unique<StickerPremiumMark>(
&_controller->session(),
st::giftBoxHiddenMark,
RectPart::Center)) {
start();
}
@ -312,8 +318,11 @@ void ListWidget::selectionAction(SelectionAction action) {
case SelectionAction::Clear: clearSelected(); return;
case SelectionAction::Forward: forwardSelected(); return;
case SelectionAction::Delete: deleteSelected(); return;
case SelectionAction::ToggleStoryInProfile:
toggleStoryInProfileSelected();
case SelectionAction::ToggleStoryToProfile:
toggleStoryInProfileSelected(true);
return;
case SelectionAction::ToggleStoryToArchive:
toggleStoryInProfileSelected(false);
return;
case SelectionAction::ToggleStoryPin: toggleStoryPinSelected(); return;
}
@ -395,6 +404,7 @@ auto ListWidget::collectSelectedItems() const -> SelectedItems {
result.canForward = selection.canForward;
result.canToggleStoryPin = selection.canToggleStoryPin;
result.canUnpinStory = selection.canUnpinStory;
result.storyInProfile = selection.storyInProfile;
return result;
};
auto transformation = [&](const auto &item) {
@ -527,6 +537,10 @@ bool ListWidget::itemVisible(not_null<const BaseLayout*> item) {
return true;
}
not_null<StickerPremiumMark*> ListWidget::hiddenMark() {
return _hiddenMark.get();
}
QString ListWidget::tooltipText() const {
if (const auto link = ClickHandler::getActive()) {
return link->tooltip();
@ -1020,6 +1034,11 @@ void ListWidget::showContextMenu(
return !item.second.canToggleStoryPin;
});
};
const auto allInProfile = [&] {
return ranges::all_of(_selected, [](auto &&item) {
return item.second.storyInProfile;
});
};
const auto canUnpinStoryAll = [&] {
return ranges::any_of(_selected, [](auto &&item) {
return item.second.canUnpinStory;
@ -1125,13 +1144,14 @@ void ListWidget::showContextMenu(
}
if (overSelected == SelectionState::OverSelectedItems) {
if (canToggleStoryPinAll()) {
const auto albumId = _controller->storiesAlbumId();
const auto toProfile = (albumId == Stories::ArchiveId());
const auto toProfile = !allInProfile();
_contextMenu->addAction(
(toProfile
? tr::lng_mediaview_save_to_profile
: tr::lng_archived_add)(tr::now),
crl::guard(this, [this] { toggleStoryInProfileSelected(); }),
crl::guard(this, [=] {
toggleStoryInProfileSelected(toProfile);
}),
(toProfile
? &st::menuIconStoriesSave
: &st::menuIconStoriesArchive));
@ -1177,14 +1197,15 @@ void ListWidget::showContextMenu(
item,
FullSelection);
if (selectionData.canToggleStoryPin) {
const auto albumId = _controller->storiesAlbumId();
const auto toProfile = (albumId == Stories::ArchiveId());
const auto toProfile = !selectionData.storyInProfile;
_contextMenu->addAction(
(toProfile
? tr::lng_mediaview_save_to_profile
: tr::lng_mediaview_archive_story)(tr::now),
crl::guard(this, [=] {
toggleStoryInProfile({ 1, globalId.itemId });
toggleStoryInProfile(
{ 1, globalId.itemId },
toProfile);
}),
(toProfile
? &st::menuIconStoriesSave
@ -1317,10 +1338,11 @@ void ListWidget::deleteSelected() {
}));
}
void ListWidget::toggleStoryInProfileSelected() {
toggleStoryInProfile(collectSelectedIds(), crl::guard(this, [=] {
clearSelected();
}));
void ListWidget::toggleStoryInProfileSelected(bool toProfile) {
toggleStoryInProfile(
collectSelectedIds(),
toProfile,
crl::guard(this, [=] { clearSelected(); }));
}
void ListWidget::toggleStoryPinSelected() {
@ -1335,6 +1357,7 @@ void ListWidget::toggleStoryPinSelected() {
void ListWidget::toggleStoryInProfile(
MessageIdsList &&items,
bool toProfile,
Fn<void()> confirmed) {
auto list = std::vector<FullStoryId>();
for (const auto &id : items) {
@ -1347,8 +1370,6 @@ void ListWidget::toggleStoryInProfile(
}
const auto channel = peerIsChannel(list.front().peer);
const auto count = int(list.size());
const auto albumId = _controller->storiesAlbumId();
const auto toProfile = (albumId == Stories::ArchiveId());
const auto controller = _controller;
const auto sure = [=](Fn<void()> close) {
using namespace ::Media::Stories;

View File

@ -84,6 +84,7 @@ public:
void unregisterHeavyItem(not_null<const BaseLayout*> item) override;
void repaintItem(not_null<const BaseLayout*> item) override;
bool itemVisible(not_null<const BaseLayout*> item) override;
not_null<StickerPremiumMark*> hiddenMark() override;
// AbstractTooltipShower interface
QString tooltipText() const override;
@ -192,11 +193,12 @@ private:
void forwardItems(MessageIdsList &&items);
void deleteSelected();
void toggleStoryPinSelected();
void toggleStoryInProfileSelected();
void toggleStoryInProfileSelected(bool toProfile);
void deleteItem(GlobalMsgId globalId);
void deleteItems(SelectedItems &&items, Fn<void()> confirmed = nullptr);
void toggleStoryInProfile(
MessageIdsList &&items,
bool toProfile,
Fn<void()> confirmed = nullptr);
void toggleStoryPin(
MessageIdsList &&items,
@ -311,6 +313,7 @@ private:
int _storiesAddToAlbumId = 0;
base::flat_set<StoryId> _storiesInAlbum;
base::flat_set<MsgId> _storyMsgsToMarkSelected;
std::unique_ptr<StickerPremiumMark> _hiddenMark;
base::unique_qptr<Ui::PopupMenu> _contextMenu;
rpl::event_stream<> _checkForHide;

View File

@ -947,10 +947,8 @@ void InnerWidget::refreshAbout() {
auto text = tr::lng_peer_gifts_empty_search(
tr::now,
Ui::Text::RichLangValue);
if (_entries->total > 0) {
text.append("\n\n").append(Ui::Text::Link(
tr::lng_peer_gifts_view_all(tr::now)));
}
auto about = std::make_unique<Ui::FlatLabel>(
this,
rpl::single(text),

View File

@ -552,17 +552,18 @@ void InnerWidget::setupEmpty() {
),
_list->heightValue()
) | rpl::start_with_next([=](auto, int listHeight) {
if (listHeight) {
_empty.destroy();
return;
const auto padding = st::infoMediaMargin;
if (const auto raw = _empty.release()) {
raw->hide();
raw->deleteLater();
}
if (listHeight <= padding.bottom() + padding.top()) {
refreshEmpty();
}
}, _list->lifetime());
}
void InnerWidget::refreshEmpty() {
_empty.destroy();
const auto albumId = _albumId.current();
const auto stories = &_controller->session().data().stories();
const auto knownEmpty = stories->albumIdsCountKnown(_peer->id, albumId);
@ -606,7 +607,6 @@ void InnerWidget::refreshEmpty() {
button->setClickedCallback([=] {
editAlbumStories(albumId);
});
empty->show();
_empty = std::move(empty);
} else {
@ -790,10 +790,11 @@ void InnerWidget::editAlbumName(int id) {
void InnerWidget::confirmDeleteAlbum(int id) {
const auto done = [=](Fn<void()> close) {
_controller->session().api().request(
MTPstories_DeleteAlbum(_peer->input, MTP_int(id))
).send();
albumRemoved(id);
const auto stories = &_controller->session().data().stories();
stories->albumDelete(_peer, id);
close();
};
_controller->uiShow()->show(Ui::MakeConfirmBox({
@ -807,7 +808,7 @@ void InnerWidget::confirmDeleteAlbum(int id) {
void InnerWidget::albumAdded(Data::StoryAlbum result) {
Expects(ranges::contains(_albums, result.id, &Data::StoryAlbum::id));
_albumId = result.id;
_albumIdChanges.fire_copy(result.id);
}
void InnerWidget::albumRenamed(int id, QString name) {
@ -821,20 +822,8 @@ void InnerWidget::albumRenamed(int id, QString name) {
void InnerWidget::albumRemoved(int id) {
auto now = _albumId.current();
if (now == id) {
_albumId = 0;
_albumIdChanges.fire_copy(0);
}
//const auto removeFrom = [&](Entries &entries) {
// for (auto &entry : entries.list) {
// entry.gift.collectionIds.erase(
// ranges::remove(entry.gift.collectionIds, id),
// end(entry.gift.collectionIds));
// }
//};
//removeFrom(_all);
//for (auto &[_, entries] : _perCollection) {
// removeFrom(entries);
//}
const auto i = ranges::find(_albums, id, &Data::StoryAlbum::id);
if (i != end(_albums)) {
_albums.erase(i);
@ -908,14 +897,6 @@ int InnerWidget::recountHeight() {
}
void InnerWidget::setScrollHeightValue(rpl::producer<int> value) {
//using namespace rpl::mappers;
//_empty->setFullHeight(rpl::combine(
// std::move(value),
// _listTops.events_starting_with(
// _list->topValue()
// ) | rpl::flatten_latest(),
// _topHeight.value(),
// _1 - _2 + _3));
}
rpl::producer<Ui::ScrollToRequest> InnerWidget::scrollToRequests() const {

View File

@ -343,10 +343,20 @@ std::unique_ptr<BaseLayout> Provider::createLayout(
}
return nullptr;
};
const auto peer = item->history()->peer;
const auto channel = peer->asChannel();
const auto showPinned = (_albumId == Data::kStoriesAlbumIdSaved);
const auto showHidden = peer->isSelf()
|| (channel && channel->canEditStories());
using namespace Overview::Layout;
const auto options = MediaOptions{
.pinned = item->isPinned(),
.story = true,
.storyPinned = showPinned && item->isPinned(),
.storyShowPinned = showPinned,
.storyHidden = showHidden && !item->storyInProfile(),
.storyShowHidden = showHidden,
};
if (const auto photo = getPhoto()) {
return std::make_unique<Photo>(delegate, item, photo, options);
@ -379,6 +389,7 @@ ListItemSelectionData Provider::computeSelectionData(
result.canForward = peer->isSelf() && story->canShare();
result.canDelete = story->canDelete();
result.canUnpinStory = story->pinnedToTop();
result.storyInProfile = story->inProfile();
}
result.canToggleStoryPin = peer->isSelf()
|| (channel && channel->canEditStories());

View File

@ -248,7 +248,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason;
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
userFull#29de80be flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating = UserFull;
userFull#7e63ce1f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int = UserFull;
contact#145ade0b user_id:long mutual:Bool = Contact;
@ -2001,7 +2001,7 @@ storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo i
stories.albumsNotModified#564edaeb = stories.Albums;
stories.albums#c3987a3a hash:long albums:Vector<StoryAlbum> = stories.Albums;
searchPostsFlood#940e707c flags:# remains:int wait_till:flags.0?int stars_amount:long = SearchPostsFlood;
searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood;
---functions---
@ -2530,7 +2530,7 @@ channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?strin
channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates;
channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates;
channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User;
channels.checkSearchPostsFlood#bba9f121 = SearchPostsFlood;
channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;

View File

@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/media/history_view_media_common.h"
#include "history/view/media/history_view_document.h" // DrawThumbnailAsSongCover
#include "base/unixtime.h"
#include "boxes/sticker_set_box.h"
#include "ui/effects/round_checkbox.h"
#include "ui/effects/spoiler_mess.h"
#include "ui/image/image.h"
@ -355,8 +356,11 @@ Photo::Photo(
})
: nullptr)
, _sensitiveSpoiler(parent->isMediaSensitive() ? 1 : 0)
, _pinned(options.pinned)
, _story(options.story)
, _storyPinned(options.storyPinned)
, _storyShowPinned(options.storyShowPinned)
, _storyHidden(options.storyHidden)
, _storyShowHidden(options.storyShowHidden)
, _link(_sensitiveSpoiler
? HistoryView::MakeSensitiveMediaLink(
std::make_shared<LambdaClickHandler>(crl::guard(this, [=] {
@ -408,7 +412,7 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const
|| _dataMedia->image(Data::PhotoSize::Thumbnail));
if ((good && !_goodLoaded) || widthChanged) {
_goodLoaded = good;
_pix = QPixmap();
_pix = QImage();
if (_goodLoaded) {
setPixFrom(_dataMedia->image(Data::PhotoSize::Large)
? _dataMedia->image(Data::PhotoSize::Large)
@ -426,7 +430,7 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const
if (_pix.isNull()) {
p.fillRect(0, 0, _width, _height, st::overviewPhotoBg);
} else {
p.drawPixmap(0, 0, _pix);
p.drawImage(0, 0, _pix);
}
if (_spoiler) {
@ -442,11 +446,21 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const
}
}
if (_storyHidden) {
delegate()->hiddenMark()->paint(
p,
_pix,
_hiddenBgCache,
QPoint(),
QSize(_width, _height),
_width);
}
if (selected) {
p.fillRect(0, 0, _width, _height, st::overviewPhotoSelectOverlay);
}
if (_pinned) {
if (_storyPinned) {
const auto &icon = selected
? st::storyPinnedIconSelected
: st::storyPinnedIcon;
@ -466,8 +480,7 @@ void Photo::setPixFrom(not_null<Image*> image) {
if (!_goodLoaded) {
img = Images::Blur(std::move(img));
}
_pix = Ui::PixmapFromImage(
CropMediaFrame(std::move(img), _width, _height));
_pix = CropMediaFrame(std::move(img), _width, _height);
// In case we have inline thumbnail we can unload all images and we still
// won't get a blank image in the media viewer when the photo is opened.
@ -493,7 +506,7 @@ void Photo::clearSpoiler() {
if (_spoiler) {
_spoiler = nullptr;
_sensitiveSpoiler = false;
_pix = QPixmap();
_pix = QImage();
delegate()->repaintItem(this);
}
}
@ -506,9 +519,11 @@ void Photo::maybeClearSensitiveSpoiler() {
}
void Photo::itemDataChanged() {
const auto pinned = parent()->isPinned();
if (_pinned != pinned) {
_pinned = pinned;
const auto pinned = _storyShowPinned && parent()->isPinned();
const auto hidden = _storyShowHidden && !parent()->storyInProfile();
if (_storyPinned != pinned || _storyHidden != hidden) {
_storyPinned = pinned;
_storyHidden = hidden;
delegate()->repaintItem(this);
}
}
@ -541,8 +556,11 @@ Video::Video(
})
: nullptr)
, _sensitiveSpoiler(parent->isMediaSensitive() ? 1 : 0)
, _pinned(options.pinned)
, _story(options.story) {
, _story(options.story)
, _storyPinned(options.storyPinned)
, _storyShowPinned(options.storyShowPinned)
, _storyHidden(options.storyHidden)
, _storyShowHidden(options.storyShowHidden) {
setDocumentLinks(_data);
if (_sensitiveSpoiler) {
_openl = HistoryView::MakeSensitiveMediaLink(
@ -577,7 +595,11 @@ int32 Video::resizeGetHeight(int32 width) {
return _height;
}
void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
void Video::paint(
Painter &p,
const QRect &clip,
TextSelection selection,
const PaintContext *context) {
ensureDataMediaCreated();
const auto selected = (selection == FullSelection);
@ -614,15 +636,14 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
: thumbnail
? thumbnail->original()
: Images::Blur(blurred->original());
_pix = Ui::PixmapFromImage(
CropMediaFrame(std::move(img), _width, _height));
_pix = CropMediaFrame(std::move(img), _width, _height);
_pixBlurred = !(thumbnail || good);
}
if (_pix.isNull()) {
p.fillRect(0, 0, _width, _height, st::overviewPhotoBg);
} else {
p.drawPixmap(0, 0, _pix);
p.drawImage(0, 0, _pix);
}
if (_spoiler) {
@ -638,11 +659,21 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
}
}
if (_storyHidden) {
delegate()->hiddenMark()->paint(
p,
_pix,
_hiddenBgCache,
QPoint(),
QSize(_width, _height),
_width);
}
if (selected) {
p.fillRect(QRect(0, 0, _width, _height), st::overviewPhotoSelectOverlay);
}
if (_pinned) {
if (_storyPinned) {
const auto &icon = selected
? st::storyPinnedIconSelected
: st::storyPinnedIcon;
@ -723,7 +754,7 @@ void Video::clearSpoiler() {
if (_spoiler) {
_spoiler = nullptr;
_sensitiveSpoiler = false;
_pix = QPixmap();
_pix = QImage();
delegate()->repaintItem(this);
}
}
@ -736,9 +767,11 @@ void Video::maybeClearSensitiveSpoiler() {
}
void Video::itemDataChanged() {
const auto pinned = parent()->isPinned();
if (_pinned != pinned) {
_pinned = pinned;
const auto pinned = _storyShowPinned && parent()->isPinned();
const auto hidden = _storyShowHidden && !parent()->storyInProfile();
if (_storyPinned != pinned || _storyHidden != hidden) {
_storyPinned = pinned;
_storyHidden = hidden;
delegate()->repaintItem(this);
}
}

View File

@ -190,8 +190,11 @@ struct Info : RuntimeComponent<Info, LayoutItemBase> {
struct MediaOptions {
bool spoiler = false;
bool pinned = false;
bool story = false;
bool storyPinned = false;
bool storyShowPinned = false;
bool storyHidden = false;
bool storyShowHidden = false;
};
class Photo final : public ItemBase {
@ -225,11 +228,15 @@ private:
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
std::unique_ptr<Ui::SpoilerAnimation> _spoiler;
QPixmap _pix;
bool _goodLoaded = false;
bool _sensitiveSpoiler = false;
bool _pinned = false;
bool _story = false;
QImage _pix;
QImage _hiddenBgCache;
bool _goodLoaded : 1 = false;
bool _sensitiveSpoiler : 1 = false;
bool _story : 1 = false;
bool _storyPinned : 1 = false;
bool _storyShowPinned : 1 = false;
bool _storyHidden : 1 = false;
bool _storyShowHidden : 1 = false;
ClickHandlerPtr _link;
@ -339,11 +346,15 @@ private:
QString _duration;
std::unique_ptr<Ui::SpoilerAnimation> _spoiler;
QPixmap _pix;
bool _pixBlurred = true;
bool _sensitiveSpoiler = false;
bool _pinned = false;
bool _story = false;
QImage _pix;
QImage _hiddenBgCache;
bool _pixBlurred : 1 = true;
bool _sensitiveSpoiler : 1 = false;
bool _story : 1 = false;
bool _storyPinned : 1 = false;
bool _storyShowPinned : 1 = false;
bool _storyHidden : 1 = false;
bool _storyShowHidden : 1 = false;
};

View File

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class StickerPremiumMark;
namespace Overview {
namespace Layout {
@ -19,6 +21,8 @@ public:
virtual void repaintItem(not_null<const ItemBase*> item) = 0;
virtual bool itemVisible(not_null<const ItemBase*> item) = 0;
[[nodiscard]] virtual not_null<StickerPremiumMark*> hiddenMark() = 0;
virtual void openPhoto(not_null<PhotoData*> photo, FullMsgId id) = 0;
virtual void openDocument(
not_null<DocumentData*> document,