mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-17 22:57:11 +02:00
Add hide / unpin all button in pinned section.
This commit is contained in:
parent
61d335469f
commit
994e3d8da7
12 changed files with 254 additions and 26 deletions
|
@ -170,6 +170,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_pinned_pin" = "Pin";
|
||||
"lng_pinned_unpin" = "Unpin";
|
||||
"lng_pinned_notify" = "Notify all members";
|
||||
"lng_pinned_messages_title#one" = "{count} pinned message";
|
||||
"lng_pinned_messages_title#other" = "{count} pinned messages";
|
||||
"lng_pinned_hide_all" = "Don't show pinned messages";
|
||||
"lng_pinned_unpin_all#one" = "Unpin {count} message";
|
||||
"lng_pinned_unpin_all#other" = "Unpin all {count} messages";
|
||||
"lng_pinned_unpin_all_sure" = "Do you want to unpin all messages?";
|
||||
"lng_pinned_hide_all_sure" = "Do you want to hide the pinned messages bar? It will stay hidden until a new message is pinned.";
|
||||
"lng_pinned_hide_all_hide" = "Hide";
|
||||
|
||||
"lng_edit_media_album_error" = "This file cannot be saved as a part of an album.";
|
||||
"lng_edit_media_invalid_file" = "Sorry, no way to use this file.";
|
||||
|
@ -316,8 +324,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_settings_events_title" = "Events";
|
||||
"lng_settings_events_joined" = "Contact joined Telegram";
|
||||
"lng_settings_events_pinned" = "Pinned messages";
|
||||
"lng_pinned_messages_title#one" = "{count} pinned message";
|
||||
"lng_pinned_messages_title#other" = "{count} pinned messages";
|
||||
|
||||
"lng_notification_preview" = "You have a new message";
|
||||
"lng_notification_reply" = "Reply";
|
||||
|
|
|
@ -435,6 +435,7 @@ QString PeerData::computeUnavailableReason() const {
|
|||
return (first != filtered.end()) ? first->text : QString();
|
||||
}
|
||||
|
||||
// This is duplicated in CanPinMessagesValue().
|
||||
bool PeerData::canPinMessages() const {
|
||||
if (const auto user = asUser()) {
|
||||
return user->fullFlags() & MTPDuserFull::Flag::f_can_pin_message;
|
||||
|
@ -1028,4 +1029,16 @@ MsgId ResolveTopPinnedId(not_null<PeerData*> peer) {
|
|||
return slice.messageIds.empty() ? 0 : slice.messageIds.back();
|
||||
}
|
||||
|
||||
std::optional<int> ResolvePinnedCount(not_null<PeerData*> peer) {
|
||||
const auto slice = peer->session().storage().snapshot(
|
||||
Storage::SharedMediaQuery(
|
||||
Storage::SharedMediaKey(
|
||||
peer->id,
|
||||
Storage::SharedMediaType::Pinned,
|
||||
0),
|
||||
0,
|
||||
0));
|
||||
return slice.count;
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -444,5 +444,6 @@ std::optional<QString> RestrictionError(
|
|||
|
||||
void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId);
|
||||
[[nodiscard]] MsgId ResolveTopPinnedId(not_null<PeerData*> peer);
|
||||
[[nodiscard]] std::optional<int> ResolvePinnedCount(not_null<PeerData*> peer);
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -252,7 +252,71 @@ rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer) {
|
|||
} else if (auto channel = peer->asChannel()) {
|
||||
return CanWriteValue(channel);
|
||||
}
|
||||
Unexpected("Bad peer value in CanWriteValue()");
|
||||
Unexpected("Bad peer value in CanWriteValue");
|
||||
}
|
||||
|
||||
// This is duplicated in PeerData::canPinMessages().
|
||||
rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer) {
|
||||
using namespace rpl::mappers;
|
||||
if (const auto user = peer->asUser()) {
|
||||
return PeerFullFlagsValue(
|
||||
user,
|
||||
MTPDuserFull::Flag::f_can_pin_message
|
||||
) | rpl::map(_1 != MTPDuserFull::Flag(0));
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
const auto mask = 0
|
||||
| MTPDchat::Flag::f_deactivated
|
||||
| MTPDchat_ClientFlag::f_forbidden
|
||||
| MTPDchat::Flag::f_left
|
||||
| MTPDchat::Flag::f_creator
|
||||
| MTPDchat::Flag::f_kicked;
|
||||
return rpl::combine(
|
||||
PeerFlagsValue(chat, mask),
|
||||
AdminRightValue(chat, ChatAdminRight::f_pin_messages),
|
||||
DefaultRestrictionValue(chat, ChatRestriction::f_pin_messages),
|
||||
[](
|
||||
MTPDchat::Flags flags,
|
||||
bool adminRightAllows,
|
||||
bool defaultRestriction) {
|
||||
const auto amOutFlags = 0
|
||||
| MTPDchat::Flag::f_deactivated
|
||||
| MTPDchat_ClientFlag::f_forbidden
|
||||
| MTPDchat::Flag::f_left
|
||||
| MTPDchat::Flag::f_kicked;
|
||||
return !(flags & amOutFlags)
|
||||
&& ((flags & MTPDchat::Flag::f_creator)
|
||||
|| adminRightAllows
|
||||
|| !defaultRestriction);
|
||||
});
|
||||
} else if (const auto megagroup = peer->asMegagroup()) {
|
||||
if (megagroup->amCreator()) {
|
||||
return rpl::single(true);
|
||||
}
|
||||
return rpl::combine(
|
||||
AdminRightValue(megagroup, ChatAdminRight::f_pin_messages),
|
||||
DefaultRestrictionValue(megagroup, ChatRestriction::f_pin_messages),
|
||||
PeerFlagValue(megagroup, MTPDchannel::Flag::f_username),
|
||||
PeerFullFlagValue(megagroup, MTPDchannelFull::Flag::f_location),
|
||||
megagroup->restrictionsValue()
|
||||
) | rpl::map([=](
|
||||
bool adminRightAllows,
|
||||
bool defaultRestriction,
|
||||
bool hasUsername,
|
||||
bool hasLocation,
|
||||
Data::Flags<ChatRestrictions>::Change restrictions) {
|
||||
return adminRightAllows
|
||||
|| (!hasUsername
|
||||
&& !hasLocation
|
||||
&& !defaultRestriction
|
||||
&& !(restrictions.value & ChatRestriction::f_pin_messages));
|
||||
});
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
if (channel->amCreator()) {
|
||||
return rpl::single(true);
|
||||
}
|
||||
return AdminRightValue(channel, ChatAdminRight::f_edit_messages);
|
||||
}
|
||||
Unexpected("Peer type in CanPinMessagesValue.");
|
||||
}
|
||||
|
||||
TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now) {
|
||||
|
|
|
@ -84,6 +84,7 @@ template <
|
|||
typename = typename PeerType::FullFlags::Change>
|
||||
inline auto PeerFullFlagsValue(PeerType *peer) {
|
||||
Expects(peer != nullptr);
|
||||
|
||||
return peer->fullFlagsValue();
|
||||
}
|
||||
|
||||
|
@ -105,10 +106,11 @@ inline auto PeerFullFlagValue(
|
|||
return SingleFlagValue(PeerFullFlagsValue(peer), flag);
|
||||
}
|
||||
|
||||
rpl::producer<bool> CanWriteValue(UserData *user);
|
||||
rpl::producer<bool> CanWriteValue(ChatData *chat);
|
||||
rpl::producer<bool> CanWriteValue(ChannelData *channel);
|
||||
rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer);
|
||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(UserData *user);
|
||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(ChatData *chat);
|
||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(ChannelData *channel);
|
||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer);
|
||||
[[nodiscard]] rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now);
|
||||
[[nodiscard]] crl::time OnlineChangeTimeout(TimeId online, TimeId now);
|
||||
|
|
|
@ -5565,15 +5565,15 @@ void HistoryWidget::hidePinnedMessage() {
|
|||
{ peerToChannel(_peer->id), id.message },
|
||||
false);
|
||||
} else {
|
||||
const auto top = Data::ResolveTopPinnedId(_peer);
|
||||
if (top) {
|
||||
session().settings().setHiddenPinnedMessageId(_peer->id, top);
|
||||
session().saveSettingsDelayed();
|
||||
|
||||
checkPinnedBarState();
|
||||
} else {
|
||||
session().api().requestFullPeer(_peer);
|
||||
}
|
||||
const auto callback = [=] {
|
||||
if (_pinnedTracker) {
|
||||
checkPinnedBarState();
|
||||
}
|
||||
};
|
||||
Window::HidePinnedBar(
|
||||
controller(),
|
||||
_peer,
|
||||
crl::guard(this, callback));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -77,13 +77,17 @@ MsgId ItemIdAcrossData(not_null<HistoryItem*> item) {
|
|||
return session->data().scheduledMessages().lookupId(item);
|
||||
}
|
||||
|
||||
bool HasEditMessageAction(const ContextMenuRequest &request) {
|
||||
bool HasEditMessageAction(
|
||||
const ContextMenuRequest &request,
|
||||
not_null<ListWidget*> list) {
|
||||
const auto item = request.item;
|
||||
const auto context = list->elementContext();
|
||||
if (!item
|
||||
|| item->isSending()
|
||||
|| item->hasFailed()
|
||||
|| item->isEditingMedia()
|
||||
|| !request.selectedItems.empty()) {
|
||||
|| !request.selectedItems.empty()
|
||||
|| (context != Context::History && context != Context::Replies)) {
|
||||
return false;
|
||||
}
|
||||
const auto peer = item->history()->peer;
|
||||
|
@ -441,8 +445,10 @@ bool AddSendNowMessageAction(
|
|||
|
||||
bool AddRescheduleMessageAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
const ContextMenuRequest &request) {
|
||||
if (!HasEditMessageAction(request) || !request.item->isScheduled()) {
|
||||
const ContextMenuRequest &request,
|
||||
not_null<ListWidget*> list) {
|
||||
if (!HasEditMessageAction(request, list)
|
||||
|| !request.item->isScheduled()) {
|
||||
return false;
|
||||
}
|
||||
const auto owner = &request.item->history()->owner();
|
||||
|
@ -551,7 +557,7 @@ bool AddEditMessageAction(
|
|||
not_null<Ui::PopupMenu*> menu,
|
||||
const ContextMenuRequest &request,
|
||||
not_null<ListWidget*> list) {
|
||||
if (!HasEditMessageAction(request)) {
|
||||
if (!HasEditMessageAction(request, list)) {
|
||||
return false;
|
||||
}
|
||||
const auto item = request.item;
|
||||
|
@ -591,6 +597,29 @@ bool AddPinMessageAction(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool AddGoToMessageAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
const ContextMenuRequest &request,
|
||||
not_null<ListWidget*> list) {
|
||||
const auto context = list->elementContext();
|
||||
const auto view = request.view;
|
||||
if (!view
|
||||
|| !IsServerMsgId(view->data()->id)
|
||||
|| context != Context::Pinned
|
||||
|| !view->hasOutLayout()) {
|
||||
return false;
|
||||
}
|
||||
const auto itemId = view->data()->fullId();
|
||||
const auto controller = list->controller();
|
||||
menu->addAction(tr::lng_context_to_msg(tr::now), crl::guard(controller, [=] {
|
||||
const auto item = controller->session().data().message(itemId);
|
||||
if (item) {
|
||||
goToMessageClickHandler(item)->onClick(ClickContext{});
|
||||
}
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddSendNowAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
const ContextMenuRequest &request,
|
||||
|
@ -774,6 +803,7 @@ void AddTopMessageActions(
|
|||
const ContextMenuRequest &request,
|
||||
not_null<ListWidget*> list) {
|
||||
AddReplyToMessageAction(menu, request, list);
|
||||
AddGoToMessageAction(menu, request, list);
|
||||
AddViewRepliesAction(menu, request, list);
|
||||
AddEditMessageAction(menu, request, list);
|
||||
AddPinMessageAction(menu, request, list);
|
||||
|
@ -789,7 +819,7 @@ void AddMessageActions(
|
|||
AddDeleteAction(menu, request, list);
|
||||
AddReportAction(menu, request, list);
|
||||
AddSelectionAction(menu, request, list);
|
||||
AddRescheduleMessageAction(menu, request);
|
||||
AddRescheduleMessageAction(menu, request, list);
|
||||
}
|
||||
|
||||
void AddCopyLinkAction(
|
||||
|
|
|
@ -1316,6 +1316,7 @@ void ListWidget::updateItemsGeometry() {
|
|||
view->setDisplayDate(false);
|
||||
} else {
|
||||
view->setDisplayDate(true);
|
||||
view->setAttachToPrevious(false);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -2611,6 +2612,9 @@ void ListWidget::refreshAttachmentsFromTill(int from, int till) {
|
|||
view = next;
|
||||
}
|
||||
}
|
||||
if (till == int(_items.size())) {
|
||||
_items.back()->setAttachToNext(false);
|
||||
}
|
||||
updateSize();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history_item_components.h"
|
||||
#include "history/history_item.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
|
@ -93,6 +94,10 @@ PinnedWidget::PinnedWidget(
|
|||
, _topBar(this, controller)
|
||||
, _topBarShadow(this)
|
||||
, _scroll(std::make_unique<Ui::ScrollArea>(this, st::historyScroll, false))
|
||||
, _clearButton(std::make_unique<Ui::FlatButton>(
|
||||
this,
|
||||
QString(),
|
||||
st::historyComposeButton))
|
||||
, _scrollDown(_scroll.get(), st::historyToDown) {
|
||||
_topBar->setActiveChat(
|
||||
_history,
|
||||
|
@ -129,6 +134,7 @@ PinnedWidget::PinnedWidget(
|
|||
_scroll->show();
|
||||
connect(_scroll.get(), &Ui::ScrollArea::scrolled, [=] { onScroll(); });
|
||||
|
||||
setupClearButton();
|
||||
setupScrollDownButton();
|
||||
}
|
||||
|
||||
|
@ -149,6 +155,28 @@ void PinnedWidget::setupScrollDownButton() {
|
|||
updateScrollDownVisibility();
|
||||
}
|
||||
|
||||
void PinnedWidget::setupClearButton() {
|
||||
Data::CanPinMessagesValue(
|
||||
_history->peer
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshClearButtonText();
|
||||
}, _clearButton->lifetime());
|
||||
|
||||
_clearButton->setClickedCallback([=] {
|
||||
if (!_history->peer->canPinMessages()) {
|
||||
const auto callback = [=] {
|
||||
controller()->showBackFromStack();
|
||||
};
|
||||
Window::HidePinnedBar(
|
||||
controller(),
|
||||
_history->peer,
|
||||
crl::guard(this, callback));
|
||||
} else {
|
||||
Window::UnpinAllMessages(controller(), _history);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PinnedWidget::scrollDownClicked() {
|
||||
if (QGuiApplication::keyboardModifiers() == Qt::ControlModifier) {
|
||||
showAtEnd();
|
||||
|
@ -357,6 +385,26 @@ void PinnedWidget::recountChatWidth() {
|
|||
}
|
||||
}
|
||||
|
||||
void PinnedWidget::setMessagesCount(int count) {
|
||||
if (_messagesCount == count) {
|
||||
return;
|
||||
}
|
||||
_messagesCount = count;
|
||||
_topBar->setCustomTitle(
|
||||
tr::lng_pinned_messages_title(tr::now, lt_count, count));
|
||||
refreshClearButtonText();
|
||||
}
|
||||
|
||||
void PinnedWidget::refreshClearButtonText() {
|
||||
const auto can = _history->peer->canPinMessages();
|
||||
_clearButton->setText(can
|
||||
? tr::lng_pinned_unpin_all(
|
||||
tr::now,
|
||||
lt_count,
|
||||
std::max(_messagesCount, 1)).toUpper()
|
||||
: tr::lng_pinned_hide_all(tr::now).toUpper());
|
||||
}
|
||||
|
||||
void PinnedWidget::updateControlsGeometry() {
|
||||
const auto contentWidth = width();
|
||||
|
||||
|
@ -366,7 +414,9 @@ void PinnedWidget::updateControlsGeometry() {
|
|||
_topBar->resizeToWidth(contentWidth);
|
||||
_topBarShadow->resize(contentWidth, st::lineWidth);
|
||||
|
||||
const auto bottom = height();
|
||||
const auto bottom = height() - _clearButton->height();
|
||||
_clearButton->resizeToWidth(width());
|
||||
_clearButton->move(0, bottom);
|
||||
const auto controlsHeight = 0;
|
||||
const auto scrollY = _topBar->height();
|
||||
const auto scrollHeight = bottom - scrollY - controlsHeight;
|
||||
|
@ -479,8 +529,7 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
|
|||
if (!count.has_value()) {
|
||||
return true;
|
||||
} else if (*count != 0) {
|
||||
_topBar->setCustomTitle(
|
||||
tr::lng_pinned_messages_title(tr::now, lt_count, *count));
|
||||
setMessagesCount(*count);
|
||||
return true;
|
||||
} else {
|
||||
controller()->showBackFromStack();
|
||||
|
|
|
@ -120,6 +120,7 @@ private:
|
|||
HistoryItem *originItem,
|
||||
anim::type animated = anim::type::normal);
|
||||
|
||||
void setupClearButton();
|
||||
void setupScrollDownButton();
|
||||
void scrollDownClicked();
|
||||
void scrollDownAnimationFinish();
|
||||
|
@ -131,6 +132,9 @@ private:
|
|||
void clearSelected();
|
||||
void recountChatWidth();
|
||||
|
||||
void setMessagesCount(int count);
|
||||
void refreshClearButtonText();
|
||||
|
||||
const not_null<History*> _history;
|
||||
QPointer<ListWidget> _inner;
|
||||
object_ptr<TopBarWidget> _topBar;
|
||||
|
@ -138,13 +142,14 @@ private:
|
|||
|
||||
bool _skipScrollEvent = false;
|
||||
std::unique_ptr<Ui::ScrollArea> _scroll;
|
||||
object_ptr<Ui::FlatButton> _clearButton = { nullptr };
|
||||
std::unique_ptr<Ui::FlatButton> _clearButton;
|
||||
|
||||
Ui::Animations::Simple _scrollDownShown;
|
||||
bool _scrollDownIsShown = false;
|
||||
object_ptr<Ui::HistoryDownButton> _scrollDown;
|
||||
|
||||
Data::MessagesSlice _lastSlice;
|
||||
int _messagesCount = -1;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1150,6 +1150,53 @@ void ToggleMessagePinned(
|
|||
}
|
||||
}
|
||||
|
||||
void HidePinnedBar(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void()> onHidden) {
|
||||
Ui::show(Box<ConfirmBox>(tr::lng_pinned_hide_all_sure(tr::now), tr::lng_pinned_hide_all_hide(tr::now), crl::guard(navigation, [=] {
|
||||
Ui::hideLayer();
|
||||
auto &session = peer->session();
|
||||
const auto top = Data::ResolveTopPinnedId(peer);
|
||||
if (top) {
|
||||
session.settings().setHiddenPinnedMessageId(peer->id, top);
|
||||
session.saveSettingsDelayed();
|
||||
if (onHidden) {
|
||||
onHidden();
|
||||
}
|
||||
} else {
|
||||
session.api().requestFullPeer(peer);
|
||||
}
|
||||
})));
|
||||
}
|
||||
|
||||
void UnpinAllMessages(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<History*> history) {
|
||||
Ui::show(Box<ConfirmBox>(tr::lng_pinned_unpin_all_sure(tr::now), tr::lng_pinned_unpin(tr::now), crl::guard(navigation, [=] {
|
||||
Ui::hideLayer();
|
||||
const auto api = &history->session().api();
|
||||
const auto peer = history->peer;
|
||||
const auto sendRequest = [=](auto self) -> void {
|
||||
api->request(MTPmessages_UnpinAllMessages(
|
||||
peer->input
|
||||
)).done([=](const MTPmessages_AffectedHistory &result) {
|
||||
const auto offset = api->applyAffectedHistory(peer, result);
|
||||
if (offset > 0) {
|
||||
self(self);
|
||||
} else {
|
||||
peer->session().storage().remove(
|
||||
Storage::SharedMediaRemoveAll(
|
||||
peer->id,
|
||||
Storage::SharedMediaType::Pinned));
|
||||
peer->setHasPinnedMessages(false);
|
||||
}
|
||||
}).send();
|
||||
};
|
||||
sendRequest(sendRequest);
|
||||
})));
|
||||
}
|
||||
|
||||
void PeerMenuAddMuteAction(
|
||||
not_null<PeerData*> peer,
|
||||
const PeerMenuCallback &addAction) {
|
||||
|
|
|
@ -115,5 +115,12 @@ void ToggleMessagePinned(
|
|||
not_null<Window::SessionNavigation*> navigation,
|
||||
FullMsgId itemId,
|
||||
bool pin);
|
||||
void HidePinnedBar(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void()> onHidden);
|
||||
void UnpinAllMessages(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<History*> history);
|
||||
|
||||
} // namespace Window
|
||||
|
|
Loading…
Add table
Reference in a new issue