init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "history/admin_log/history_admin_log_filter.h"
|
||||
|
||||
#include "boxes/peers/edit_peer_permissions_box.h"
|
||||
#include "history/admin_log/history_admin_log_filter_value.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
|
||||
namespace AdminLog {
|
||||
|
||||
EditFlagsDescriptor<FilterValue::Flags> FilterValueLabels(bool isChannel) {
|
||||
using Label = EditFlagsLabel<FilterValue::Flags>;
|
||||
using Flag = FilterValue::Flag;
|
||||
|
||||
const auto adminRights = Flag::Promote | Flag::Demote;
|
||||
const auto restrictions = Flag::Ban
|
||||
| Flag::Unban
|
||||
| Flag::Kick
|
||||
| Flag::Unkick;
|
||||
const auto membersNew = Flag::Join | Flag::Invite;
|
||||
const auto membersRemoved = Flag::Leave;
|
||||
auto membersNewText = (isChannel
|
||||
? tr::lng_admin_log_filter_subscribers_new
|
||||
: tr::lng_admin_log_filter_members_new)(tr::now);
|
||||
auto membersRemovedText = (isChannel
|
||||
? tr::lng_admin_log_filter_subscribers_removed
|
||||
: tr::lng_admin_log_filter_members_removed)(tr::now);
|
||||
|
||||
auto members = std::vector<Label>{
|
||||
{ adminRights, tr::lng_admin_log_filter_admins_new(tr::now) },
|
||||
{ restrictions, tr::lng_admin_log_filter_restrictions(tr::now) },
|
||||
{ membersNew, std::move(membersNewText) },
|
||||
{ membersRemoved, std::move(membersRemovedText) },
|
||||
};
|
||||
|
||||
const auto info = Flag::Info | Flag::Settings;
|
||||
const auto invites = Flag::Invites;
|
||||
const auto calls = Flag::GroupCall;
|
||||
auto settings = std::vector<Label>{
|
||||
{
|
||||
info,
|
||||
((!isChannel)
|
||||
? tr::lng_admin_log_filter_info_group
|
||||
: tr::lng_admin_log_filter_info_channel)(tr::now),
|
||||
},
|
||||
{ invites, tr::lng_admin_log_filter_invite_links(tr::now) },
|
||||
{
|
||||
calls,
|
||||
((!isChannel)
|
||||
? tr::lng_admin_log_filter_voice_chats
|
||||
: tr::lng_admin_log_filter_voice_chats_channel)(tr::now),
|
||||
},
|
||||
{
|
||||
Flag::SubExtend,
|
||||
tr::lng_admin_log_filter_sub_extend(tr::now),
|
||||
},
|
||||
};
|
||||
if (!isChannel) {
|
||||
settings.push_back({
|
||||
Flag::Topics,
|
||||
tr::lng_admin_log_filter_topics(tr::now),
|
||||
});
|
||||
}
|
||||
const auto deleted = Flag::Delete;
|
||||
const auto edited = Flag::Edit;
|
||||
const auto pinned = Flag::Pinned;
|
||||
auto messages = std::vector<Label>{
|
||||
{ deleted, tr::lng_admin_log_filter_messages_deleted(tr::now) },
|
||||
{ edited, tr::lng_admin_log_filter_messages_edited(tr::now) },
|
||||
};
|
||||
if (!isChannel) {
|
||||
messages.push_back({
|
||||
pinned,
|
||||
tr::lng_admin_log_filter_messages_pinned(tr::now),
|
||||
});
|
||||
}
|
||||
return { .labels = {
|
||||
{
|
||||
!isChannel
|
||||
? tr::lng_admin_log_filter_actions_member_section()
|
||||
: tr::lng_admin_log_filter_actions_subscriber_section(),
|
||||
std::move(members),
|
||||
},
|
||||
{
|
||||
!isChannel
|
||||
? tr::lng_admin_log_filter_actions_settings_section()
|
||||
: tr::lng_admin_log_filter_actions_channel_settings_section(),
|
||||
std::move(settings),
|
||||
},
|
||||
{
|
||||
tr::lng_admin_log_filter_actions_messages_section(),
|
||||
std::move(messages),
|
||||
},
|
||||
}, .st = nullptr };
|
||||
}
|
||||
|
||||
Fn<FilterValue::Flags()> FillFilterValueList(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
bool isChannel,
|
||||
const FilterValue &filter) {
|
||||
auto [checkboxes, getResult, changes] = CreateEditAdminLogFilter(
|
||||
container,
|
||||
filter.flags ? (*filter.flags) : ~FilterValue::Flags(0),
|
||||
isChannel);
|
||||
container->add(std::move(checkboxes));
|
||||
return getResult;
|
||||
}
|
||||
|
||||
} // namespace AdminLog
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "history/admin_log/history_admin_log_filter_value.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
template <typename Flags>
|
||||
struct EditFlagsDescriptor;
|
||||
|
||||
namespace Ui {
|
||||
class VerticalLayout;
|
||||
} // namespace Ui
|
||||
|
||||
namespace AdminLog {
|
||||
|
||||
struct FilterValue;
|
||||
|
||||
[[nodiscard]] Fn<FilterValue::Flags()> FillFilterValueList(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
bool isChannel,
|
||||
const FilterValue &filter);
|
||||
|
||||
EditFlagsDescriptor<FilterValue::Flags> FilterValueLabels(bool isChannel);
|
||||
|
||||
} // namespace AdminLog
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace AdminLog {
|
||||
|
||||
struct FilterValue final {
|
||||
enum class Flag : uint32 {
|
||||
Join = (1U << 0),
|
||||
Leave = (1U << 1),
|
||||
Invite = (1U << 2),
|
||||
Ban = (1U << 3),
|
||||
Unban = (1U << 4),
|
||||
Kick = (1U << 5),
|
||||
Unkick = (1U << 6),
|
||||
Promote = (1U << 7),
|
||||
Demote = (1U << 8),
|
||||
Info = (1U << 9),
|
||||
Settings = (1U << 10),
|
||||
Pinned = (1U << 11),
|
||||
Edit = (1U << 12),
|
||||
Delete = (1U << 13),
|
||||
GroupCall = (1U << 14),
|
||||
Invites = (1U << 15),
|
||||
Topics = (1U << 16),
|
||||
SubExtend = (1U << 17),
|
||||
|
||||
MAX_FIELD = (1U << 17),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr bool is_flag_type(Flag) { return true; };
|
||||
|
||||
// Std::nullopt "flags" means all events.
|
||||
std::optional<Flags> flags = std::nullopt;
|
||||
// Std::nullopt admins means all users.
|
||||
std::optional<std::vector<not_null<UserData*>>> admins = std::nullopt;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator==(const FilterValue &a, const FilterValue &b) {
|
||||
return (a.flags == b.flags) && (a.admins == b.admins);
|
||||
}
|
||||
|
||||
inline bool operator!=(const FilterValue &a, const FilterValue &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
} // namespace AdminLog
|
||||
2136
Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
Normal file
2136
Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
Normal file
File diff suppressed because it is too large
Load Diff
351
Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h
Normal file
351
Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "history/admin_log/history_admin_log_item.h"
|
||||
#include "history/admin_log/history_admin_log_filter_value.h"
|
||||
#include "menu/menu_antispam_validator.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
struct ChatRestrictionsInfo;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace HistoryView {
|
||||
class Element;
|
||||
struct TextState;
|
||||
struct StateRequest;
|
||||
enum class CursorState : char;
|
||||
enum class PointState : char;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
class ChatStyle;
|
||||
class ChatTheme;
|
||||
struct PeerUserpicView;
|
||||
struct ChatPaintContext;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace AdminLog {
|
||||
|
||||
class SectionMemento;
|
||||
|
||||
class InnerWidget final
|
||||
: public Ui::RpWidget
|
||||
, public Ui::AbstractTooltipShower
|
||||
, public HistoryView::ElementDelegate {
|
||||
public:
|
||||
InnerWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<ChannelData*> channel);
|
||||
|
||||
[[nodiscard]] Main::Session &session() const;
|
||||
[[nodiscard]] not_null<Ui::ChatTheme*> theme() const {
|
||||
return _theme.get();
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<> showSearchSignal() const;
|
||||
[[nodiscard]] rpl::producer<int> scrollToSignal() const;
|
||||
[[nodiscard]] rpl::producer<> cancelSignal() const;
|
||||
|
||||
[[nodiscard]] not_null<ChannelData*> channel() const {
|
||||
return _channel;
|
||||
}
|
||||
|
||||
Ui::ChatPaintContext preparePaintContext(QRect clip) const;
|
||||
|
||||
// Set the correct scroll position after being resized.
|
||||
void restoreScrollPosition();
|
||||
|
||||
void resizeToWidth(int newWidth, int minHeight) {
|
||||
_minHeight = minHeight;
|
||||
return RpWidget::resizeToWidth(newWidth);
|
||||
}
|
||||
|
||||
void saveState(not_null<SectionMemento*> memento);
|
||||
void restoreState(not_null<SectionMemento*> memento);
|
||||
|
||||
// Empty "flags" means all events.
|
||||
void applyFilter(FilterValue &&value);
|
||||
void applySearch(const QString &query);
|
||||
void showFilter(Fn<void(FilterValue &&filter)> callback);
|
||||
|
||||
// Ui::AbstractTooltipShower interface.
|
||||
QString tooltipText() const override;
|
||||
QPoint tooltipPos() const override;
|
||||
bool tooltipWindowActive() const override;
|
||||
|
||||
// HistoryView::ElementDelegate interface.
|
||||
HistoryView::Context elementContext() override;
|
||||
bool elementUnderCursor(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
HistoryView::SelectionModeResult elementInSelectionMode(
|
||||
const HistoryView::Element *view) override;
|
||||
bool elementIntersectsRange(
|
||||
not_null<const HistoryView::Element*> view,
|
||||
int from,
|
||||
int till) override;
|
||||
void elementStartStickerLoop(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
void elementShowPollResults(
|
||||
not_null<PollData*> poll,
|
||||
FullMsgId context) override;
|
||||
void elementOpenPhoto(
|
||||
not_null<PhotoData*> photo,
|
||||
FullMsgId context) override;
|
||||
void elementOpenDocument(
|
||||
not_null<DocumentData*> document,
|
||||
FullMsgId context,
|
||||
bool showInMediaView = false) override;
|
||||
void elementCancelUpload(const FullMsgId &context) override;
|
||||
void elementShowTooltip(
|
||||
const TextWithEntities &text,
|
||||
Fn<void()> hiddenCallback) override;
|
||||
bool elementAnimationsPaused() override;
|
||||
bool elementHideReply(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
bool elementShownUnread(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
void elementSendBotCommand(
|
||||
const QString &command,
|
||||
const FullMsgId &context) override;
|
||||
void elementSearchInList(
|
||||
const QString &query,
|
||||
const FullMsgId &context) override;
|
||||
void elementHandleViaClick(not_null<UserData*> bot) override;
|
||||
HistoryView::ElementChatMode elementChatMode() override;
|
||||
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
|
||||
void elementReplyTo(const FullReplyTo &to) override;
|
||||
void elementStartInteraction(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
void elementStartPremium(
|
||||
not_null<const HistoryView::Element*> view,
|
||||
HistoryView::Element *replacing) override;
|
||||
void elementCancelPremium(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
void elementStartEffect(
|
||||
not_null<const HistoryView::Element*> view,
|
||||
HistoryView::Element *replacing) override;
|
||||
QString elementAuthorRank(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
bool elementHideTopicButton(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
|
||||
~InnerWidget();
|
||||
|
||||
protected:
|
||||
void visibleTopBottomUpdated(
|
||||
int visibleTop,
|
||||
int visibleBottom) override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
||||
void enterEventHook(QEnterEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||
|
||||
// Resizes content and counts natural widget height for the desired width.
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
using Element = HistoryView::Element;
|
||||
enum class Direction {
|
||||
Up,
|
||||
Down,
|
||||
};
|
||||
enum class MouseAction {
|
||||
None,
|
||||
PrepareDrag,
|
||||
Dragging,
|
||||
Selecting,
|
||||
};
|
||||
enum class EnumItemsDirection {
|
||||
TopToBottom,
|
||||
BottomToTop,
|
||||
};
|
||||
using TextState = HistoryView::TextState;
|
||||
using CursorState = HistoryView::CursorState;
|
||||
using PointState = HistoryView::PointState;
|
||||
using StateRequest = HistoryView::StateRequest;
|
||||
|
||||
void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button);
|
||||
void mouseActionUpdate(const QPoint &screenPos);
|
||||
void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button);
|
||||
void mouseActionCancel();
|
||||
void updateSelected();
|
||||
void performDrag();
|
||||
int itemTop(not_null<const Element*> view) const;
|
||||
void repaintItem(const Element *view);
|
||||
void refreshItem(not_null<const Element*> view);
|
||||
void resizeItem(not_null<Element*> view);
|
||||
QPoint mapPointToItem(QPoint point, const Element *view) const;
|
||||
|
||||
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
|
||||
void savePhotoToFile(not_null<PhotoData*> photo);
|
||||
void saveDocumentToFile(not_null<DocumentData*> document);
|
||||
void copyContextImage(not_null<PhotoData*> photo);
|
||||
void showStickerPackInfo(not_null<DocumentData*> document);
|
||||
void cancelContextDownload(not_null<DocumentData*> document);
|
||||
void showContextInFolder(not_null<DocumentData*> document);
|
||||
void openContextGif(FullMsgId itemId);
|
||||
void copyContextText(FullMsgId itemId);
|
||||
void copySelectedText();
|
||||
TextForMimeData getSelectedText() const;
|
||||
void suggestRestrictParticipant(not_null<PeerData*> participant);
|
||||
void restrictParticipant(
|
||||
not_null<PeerData*> participant,
|
||||
ChatRestrictionsInfo oldRights,
|
||||
ChatRestrictionsInfo newRights);
|
||||
void restrictParticipantDone(
|
||||
not_null<PeerData*> participant,
|
||||
ChatRestrictionsInfo rights);
|
||||
|
||||
void requestAdmins();
|
||||
void checkPreloadMore();
|
||||
void updateVisibleTopItem();
|
||||
void preloadMore(Direction direction);
|
||||
void itemsAdded(Direction direction, int addedCount);
|
||||
void updateSize();
|
||||
void updateMinMaxIds();
|
||||
void updateEmptyText();
|
||||
void paintEmpty(Painter &p, not_null<const Ui::ChatStyle*> st);
|
||||
void clearAfterFilterChange();
|
||||
void clearAndRequestLog();
|
||||
void addEvents(
|
||||
Direction direction,
|
||||
const QVector<MTPChannelAdminLogEvent> &events);
|
||||
[[nodiscard]] Element *viewForItem(const HistoryItem *item);
|
||||
[[nodiscard]] bool myView(
|
||||
not_null<const HistoryView::Element*> view) const;
|
||||
|
||||
void toggleScrollDateShown();
|
||||
void repaintScrollDateCallback();
|
||||
bool displayScrollDate() const;
|
||||
void scrollDateHide();
|
||||
void scrollDateCheck();
|
||||
void scrollDateHideByTimer();
|
||||
|
||||
// This function finds all history items that are displayed and calls template method
|
||||
// for each found message (in given direction) in the passed history with passed top offset.
|
||||
//
|
||||
// Method has "bool (*Method)(not_null<Element*> view, int itemtop, int itembottom)" signature
|
||||
// if it returns false the enumeration stops immediately.
|
||||
template <EnumItemsDirection direction, typename Method>
|
||||
void enumerateItems(Method method);
|
||||
|
||||
// This function finds all userpics on the left that are displayed and calls template method
|
||||
// for each found userpic (from the top to the bottom) using enumerateItems() method.
|
||||
//
|
||||
// Method has "bool (*Method)(not_null<Element*> view, int userpicTop)" signature
|
||||
// if it returns false the enumeration stops immediately.
|
||||
template <typename Method>
|
||||
void enumerateUserpics(Method method);
|
||||
|
||||
// This function finds all date elements that are displayed and calls template method
|
||||
// for each found date element (from the bottom to the top) using enumerateItems() method.
|
||||
//
|
||||
// Method has "bool (*Method)(not_null<HistoryItem*> item, int itemtop, int dateTop)" signature
|
||||
// if it returns false the enumeration stops immediately.
|
||||
template <typename Method>
|
||||
void enumerateDates(Method method);
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<ChannelData*> _channel;
|
||||
const not_null<History*> _history;
|
||||
MTP::Sender _api;
|
||||
|
||||
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
|
||||
std::shared_ptr<Ui::ChatTheme> _theme;
|
||||
|
||||
std::vector<OwnedItem> _items;
|
||||
std::set<uint64> _eventIds;
|
||||
std::map<not_null<const HistoryItem*>, not_null<Element*>> _itemsByData;
|
||||
base::flat_map<not_null<const HistoryItem*>, TimeId> _itemDates;
|
||||
base::flat_set<FullMsgId> _animatedStickersPlayed;
|
||||
base::flat_map<not_null<PeerData*>, Ui::PeerUserpicView> _userpics;
|
||||
base::flat_map<not_null<PeerData*>, Ui::PeerUserpicView> _userpicsCache;
|
||||
int _itemsTop = 0;
|
||||
int _itemsWidth = 0;
|
||||
int _itemsHeight = 0;
|
||||
|
||||
int _minHeight = 0;
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
Element *_visibleTopItem = nullptr;
|
||||
int _visibleTopFromItem = 0;
|
||||
|
||||
bool _isChatWide = false;
|
||||
bool _scrollDateShown = false;
|
||||
Ui::Animations::Simple _scrollDateOpacity;
|
||||
SingleQueuedInvokation _scrollDateCheck;
|
||||
base::Timer _scrollDateHideTimer;
|
||||
Element *_scrollDateLastItem = nullptr;
|
||||
int _scrollDateLastItemTop = 0;
|
||||
|
||||
// Up - max, Down - min.
|
||||
uint64 _maxId = 0;
|
||||
uint64 _minId = 0;
|
||||
mtpRequestId _preloadUpRequestId = 0;
|
||||
mtpRequestId _preloadDownRequestId = 0;
|
||||
|
||||
// Don't load anything until the memento was read.
|
||||
bool _upLoaded = true;
|
||||
bool _downLoaded = true;
|
||||
bool _filterChanged = false;
|
||||
Ui::Text::String _emptyText;
|
||||
|
||||
MouseAction _mouseAction = MouseAction::None;
|
||||
TextSelectType _mouseSelectType = TextSelectType::Letters;
|
||||
QPoint _dragStartPosition;
|
||||
QPoint _mousePosition;
|
||||
Element *_mouseActionItem = nullptr;
|
||||
CursorState _mouseCursorState = CursorState();
|
||||
uint16 _mouseTextSymbol = 0;
|
||||
bool _pressWasInactive = false;
|
||||
|
||||
Element *_selectedItem = nullptr;
|
||||
TextSelection _selectedText;
|
||||
bool _wasSelectedText = false; // was some text selected in current drag action
|
||||
Qt::CursorShape _cursor = style::cur_default;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
AntiSpamMenu::AntiSpamValidator _antiSpamValidator;
|
||||
|
||||
QPoint _trippleClickPoint;
|
||||
base::Timer _trippleClickTimer;
|
||||
|
||||
FilterValue _filter;
|
||||
QString _searchQuery;
|
||||
std::vector<not_null<UserData*>> _admins;
|
||||
std::vector<not_null<UserData*>> _adminsCanEdit;
|
||||
Fn<void(FilterValue &&filter)> _showFilterCallback;
|
||||
|
||||
rpl::event_stream<> _showSearchSignal;
|
||||
rpl::event_stream<int> _scrollToSignal;
|
||||
rpl::event_stream<> _cancelSignal;
|
||||
|
||||
};
|
||||
|
||||
} // namespace AdminLog
|
||||
2195
Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp
Normal file
2195
Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class History;
|
||||
|
||||
namespace HistoryView {
|
||||
class ElementDelegate;
|
||||
class Element;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace AdminLog {
|
||||
|
||||
class OwnedItem;
|
||||
|
||||
void GenerateItems(
|
||||
not_null<HistoryView::ElementDelegate*> delegate,
|
||||
not_null<History*> history,
|
||||
const MTPDchannelAdminLogEvent &event,
|
||||
Fn<void(OwnedItem item, TimeId sentDate, MsgId)> callback);
|
||||
|
||||
// Smart pointer wrapper for HistoryItem* that destroys the owned item.
|
||||
class OwnedItem {
|
||||
public:
|
||||
OwnedItem(std::nullptr_t = nullptr);
|
||||
OwnedItem(
|
||||
not_null<HistoryView::ElementDelegate*> delegate,
|
||||
not_null<HistoryItem*> data);
|
||||
OwnedItem(const OwnedItem &other) = delete;
|
||||
OwnedItem &operator=(const OwnedItem &other) = delete;
|
||||
OwnedItem(OwnedItem &&other);
|
||||
OwnedItem &operator=(OwnedItem &&other);
|
||||
~OwnedItem();
|
||||
|
||||
[[nodiscard]] HistoryView::Element *get() const {
|
||||
return _view.get();
|
||||
}
|
||||
[[nodiscard]] HistoryView::Element *operator->() const {
|
||||
return get();
|
||||
}
|
||||
[[nodiscard]] operator HistoryView::Element*() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
void refreshView(not_null<HistoryView::ElementDelegate*> delegate);
|
||||
void clearView();
|
||||
|
||||
private:
|
||||
HistoryItem *_data = nullptr;
|
||||
std::unique_ptr<HistoryView::Element> _view;
|
||||
|
||||
};
|
||||
|
||||
} // namespace AdminLog
|
||||
@@ -0,0 +1,557 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "history/admin_log/history_admin_log_section.h"
|
||||
|
||||
#include "history/admin_log/history_admin_log_inner.h"
|
||||
#include "history/admin_log/history_admin_log_filter.h"
|
||||
#include "profile/profile_back_button.h"
|
||||
#include "core/shortcuts.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/controls/swipe_handler.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/window_adaptive.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "base/timer.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_session.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_window.h"
|
||||
#include "styles/style_info.h"
|
||||
|
||||
namespace AdminLog {
|
||||
|
||||
class FixedBar final : public Ui::RpWidget {
|
||||
public:
|
||||
FixedBar(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<ChannelData*> channel);
|
||||
|
||||
[[nodiscard]] rpl::producer<> showFilterRequests() const;
|
||||
[[nodiscard]] rpl::producer<> searchCancelRequests() const;
|
||||
[[nodiscard]] rpl::producer<QString> searchRequests() const;
|
||||
|
||||
// When animating mode is enabled the content is hidden and the
|
||||
// whole fixed bar acts like a back button.
|
||||
void setAnimatingMode(bool enabled);
|
||||
|
||||
void applyFilter(const FilterValue &value);
|
||||
void goBack();
|
||||
void showSearch();
|
||||
bool setSearchFocus() {
|
||||
if (_searchShown) {
|
||||
_field->setFocus();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
void toggleSearch();
|
||||
void cancelSearch();
|
||||
void searchUpdated();
|
||||
void applySearch();
|
||||
void searchAnimationCallback();
|
||||
|
||||
not_null<Window::SessionController*> _controller;
|
||||
not_null<ChannelData*> _channel;
|
||||
object_ptr<Ui::InputField> _field;
|
||||
object_ptr<Profile::BackButton> _backButton;
|
||||
object_ptr<Ui::IconButton> _search;
|
||||
object_ptr<Ui::CrossButton> _cancel;
|
||||
object_ptr<Ui::RoundButton> _filter;
|
||||
|
||||
Ui::Animations::Simple _searchShownAnimation;
|
||||
bool _searchShown = false;
|
||||
bool _animatingMode = false;
|
||||
base::Timer _searchTimer;
|
||||
|
||||
rpl::event_stream<> _searchCancelRequests;
|
||||
rpl::event_stream<QString> _searchRequests;
|
||||
|
||||
};
|
||||
|
||||
object_ptr<Window::SectionWidget> SectionMemento::createWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
Window::Column column,
|
||||
const QRect &geometry) {
|
||||
if (column == Window::Column::Third) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = object_ptr<Widget>(parent, controller, _channel);
|
||||
result->setInternalState(geometry, this);
|
||||
return result;
|
||||
}
|
||||
|
||||
FixedBar::FixedBar(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<ChannelData*> channel)
|
||||
: RpWidget(parent)
|
||||
, _controller(controller)
|
||||
, _channel(channel)
|
||||
, _field(this, st::defaultMultiSelectSearchField, tr::lng_dlg_filter())
|
||||
, _backButton(
|
||||
this,
|
||||
&controller->session(),
|
||||
tr::lng_admin_log_title_all(tr::now),
|
||||
controller->adaptive().oneColumnValue())
|
||||
, _search(this, st::topBarSearch)
|
||||
, _cancel(this, st::historyAdminLogCancelSearch)
|
||||
, _filter(this, tr::lng_admin_log_filter(), st::topBarButton) {
|
||||
_backButton->moveToLeft(0, 0);
|
||||
_backButton->setClickedCallback([=] { goBack(); });
|
||||
_search->setClickedCallback([=] { showSearch(); });
|
||||
_cancel->setClickedCallback([=] { cancelSearch(); });
|
||||
_field->hide();
|
||||
_filter->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||
_field->cancelled(
|
||||
) | rpl::on_next([=] {
|
||||
cancelSearch();
|
||||
}, _field->lifetime());
|
||||
_field->changes(
|
||||
) | rpl::on_next([=] {
|
||||
searchUpdated();
|
||||
}, _field->lifetime());
|
||||
_field->submits(
|
||||
) | rpl::on_next([=] { applySearch(); }, _field->lifetime());
|
||||
_searchTimer.setCallback([=] { applySearch(); });
|
||||
|
||||
_cancel->hide(anim::type::instant);
|
||||
}
|
||||
|
||||
void FixedBar::applyFilter(const FilterValue &value) {
|
||||
auto hasFilter = value.flags || value.admins;
|
||||
_backButton->setText(hasFilter
|
||||
? tr::lng_admin_log_title_selected(tr::now)
|
||||
: tr::lng_admin_log_title_all(tr::now));
|
||||
}
|
||||
|
||||
void FixedBar::goBack() {
|
||||
_controller->showBackFromStack();
|
||||
}
|
||||
|
||||
void FixedBar::showSearch() {
|
||||
if (!_searchShown) {
|
||||
toggleSearch();
|
||||
}
|
||||
}
|
||||
|
||||
void FixedBar::toggleSearch() {
|
||||
_searchShown = !_searchShown;
|
||||
_cancel->toggle(_searchShown, anim::type::normal);
|
||||
_searchShownAnimation.start(
|
||||
[=] { searchAnimationCallback(); },
|
||||
_searchShown ? 0. : 1.,
|
||||
_searchShown ? 1. : 0.,
|
||||
st::historyAdminLogSearchSlideDuration);
|
||||
_search->setDisabled(_searchShown);
|
||||
if (_searchShown) {
|
||||
_field->show();
|
||||
_field->setFocus();
|
||||
} else {
|
||||
_searchCancelRequests.fire({});
|
||||
}
|
||||
}
|
||||
|
||||
void FixedBar::searchAnimationCallback() {
|
||||
if (!_searchShownAnimation.animating()) {
|
||||
_field->setVisible(_searchShown);
|
||||
_search->setIconOverride(
|
||||
_searchShown ? &st::topBarSearch.icon : nullptr,
|
||||
_searchShown ? &st::topBarSearch.icon : nullptr);
|
||||
_search->setRippleColorOverride(
|
||||
_searchShown ? &st::topBarBg : nullptr);
|
||||
_search->setCursor(
|
||||
_searchShown ? style::cur_default : style::cur_pointer);
|
||||
}
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
void FixedBar::cancelSearch() {
|
||||
if (_searchShown) {
|
||||
if (!_field->getLastText().isEmpty()) {
|
||||
_field->clear();
|
||||
_field->setFocus();
|
||||
applySearch();
|
||||
} else {
|
||||
toggleSearch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FixedBar::searchUpdated() {
|
||||
if (_field->getLastText().isEmpty()) {
|
||||
applySearch();
|
||||
} else {
|
||||
_searchTimer.callOnce(AutoSearchTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void FixedBar::applySearch() {
|
||||
_searchRequests.fire_copy(_field->getLastText());
|
||||
}
|
||||
|
||||
int FixedBar::resizeGetHeight(int newWidth) {
|
||||
auto filterLeft = newWidth - _filter->width();
|
||||
_filter->moveToLeft(filterLeft, 0);
|
||||
|
||||
auto cancelLeft = filterLeft - _cancel->width();
|
||||
_cancel->moveToLeft(cancelLeft, 0);
|
||||
|
||||
auto searchShownLeft = st::topBarArrowPadding.left();
|
||||
auto searchHiddenLeft = filterLeft - _search->width();
|
||||
auto searchShown = _searchShownAnimation.value(_searchShown ? 1. : 0.);
|
||||
auto searchCurrentLeft = anim::interpolate(searchHiddenLeft, searchShownLeft, searchShown);
|
||||
_search->moveToLeft(searchCurrentLeft, 0);
|
||||
_backButton->resizeToWidth(searchCurrentLeft);
|
||||
_backButton->moveToLeft(0, 0);
|
||||
|
||||
auto newHeight = _backButton->height();
|
||||
auto fieldLeft = searchShownLeft + _search->width();
|
||||
_field->setGeometryToLeft(fieldLeft, st::historyAdminLogSearchTop, cancelLeft - fieldLeft, _field->height());
|
||||
|
||||
return newHeight;
|
||||
}
|
||||
|
||||
rpl::producer<> FixedBar::showFilterRequests() const {
|
||||
return _filter->clicks() | rpl::to_empty;
|
||||
}
|
||||
|
||||
rpl::producer<> FixedBar::searchCancelRequests() const {
|
||||
return _searchCancelRequests.events();
|
||||
}
|
||||
|
||||
rpl::producer<QString> FixedBar::searchRequests() const {
|
||||
return _searchRequests.events();
|
||||
}
|
||||
|
||||
void FixedBar::setAnimatingMode(bool enabled) {
|
||||
if (_animatingMode != enabled) {
|
||||
_animatingMode = enabled;
|
||||
setCursor(_animatingMode ? style::cur_pointer : style::cur_default);
|
||||
if (_animatingMode) {
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, false);
|
||||
hideChildren();
|
||||
} else {
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
showChildren();
|
||||
_field->hide();
|
||||
_cancel->setVisible(false);
|
||||
}
|
||||
show();
|
||||
}
|
||||
}
|
||||
|
||||
void FixedBar::paintEvent(QPaintEvent *e) {
|
||||
if (!_animatingMode) {
|
||||
auto p = QPainter(this);
|
||||
p.fillRect(e->rect(), st::topBarBg);
|
||||
}
|
||||
}
|
||||
|
||||
void FixedBar::mousePressEvent(QMouseEvent *e) {
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
goBack();
|
||||
} else {
|
||||
RpWidget::mousePressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
Widget::Widget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<ChannelData*> channel)
|
||||
: Window::SectionWidget(parent, controller, rpl::single<PeerData*>(channel))
|
||||
, _scroll(this, st::historyScroll, false)
|
||||
, _fixedBar(this, controller, channel)
|
||||
, _fixedBarShadow(this)
|
||||
, _whatIsThis(
|
||||
this,
|
||||
tr::lng_admin_log_about(tr::now),
|
||||
st::historyComposeButton) {
|
||||
_fixedBar->move(0, 0);
|
||||
_fixedBar->resizeToWidth(width());
|
||||
_fixedBar->showFilterRequests(
|
||||
) | rpl::on_next([=] {
|
||||
showFilter();
|
||||
}, lifetime());
|
||||
_fixedBar->searchCancelRequests(
|
||||
) | rpl::on_next([=] {
|
||||
setInnerFocus();
|
||||
}, lifetime());
|
||||
_fixedBar->searchRequests(
|
||||
) | rpl::on_next([=](const QString &query) {
|
||||
_inner->applySearch(query);
|
||||
}, lifetime());
|
||||
_fixedBar->show();
|
||||
|
||||
_fixedBarShadow->raise();
|
||||
|
||||
controller->adaptive().value(
|
||||
) | rpl::on_next([=] {
|
||||
updateAdaptiveLayout();
|
||||
}, lifetime());
|
||||
|
||||
_inner = _scroll->setOwnedWidget(object_ptr<InnerWidget>(this, controller, channel));
|
||||
_inner->showSearchSignal(
|
||||
) | rpl::on_next([=] {
|
||||
_fixedBar->showSearch();
|
||||
}, lifetime());
|
||||
_inner->cancelSignal(
|
||||
) | rpl::on_next([=] {
|
||||
_fixedBar->goBack();
|
||||
}, lifetime());
|
||||
_inner->scrollToSignal(
|
||||
) | rpl::on_next([=](int top) {
|
||||
_scroll->scrollToY(top);
|
||||
}, lifetime());
|
||||
|
||||
_scroll->move(0, _fixedBar->height());
|
||||
_scroll->show();
|
||||
_scroll->scrolls(
|
||||
) | rpl::on_next([=] {
|
||||
onScroll();
|
||||
}, lifetime());
|
||||
|
||||
_whatIsThis->setClickedCallback([=] {
|
||||
controller->show(Ui::MakeInformBox(channel->isMegagroup()
|
||||
? tr::lng_admin_log_about_text()
|
||||
: tr::lng_admin_log_about_text_channel()));
|
||||
});
|
||||
|
||||
setupShortcuts();
|
||||
setupSwipeReply();
|
||||
}
|
||||
|
||||
void Widget::showFilter() {
|
||||
_inner->showFilter([this](FilterValue &&filter) {
|
||||
applyFilter(std::move(filter));
|
||||
controller()->hideLayer();
|
||||
});
|
||||
}
|
||||
|
||||
void Widget::updateAdaptiveLayout() {
|
||||
_fixedBarShadow->moveToLeft(
|
||||
controller()->adaptive().isOneColumn()
|
||||
? 0
|
||||
: st::lineWidth,
|
||||
_fixedBar->height());
|
||||
}
|
||||
|
||||
not_null<ChannelData*> Widget::channel() const {
|
||||
return _inner->channel();
|
||||
}
|
||||
|
||||
Dialogs::RowDescriptor Widget::activeChat() const {
|
||||
return {
|
||||
channel()->owner().history(channel()),
|
||||
FullMsgId(channel()->id, ShowAtUnreadMsgId)
|
||||
};
|
||||
}
|
||||
|
||||
QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
||||
if (params.withTopBarShadow) _fixedBarShadow->hide();
|
||||
auto result = Ui::GrabWidget(this);
|
||||
if (params.withTopBarShadow) _fixedBarShadow->show();
|
||||
return result;
|
||||
}
|
||||
|
||||
void Widget::doSetInnerFocus() {
|
||||
if (!_fixedBar->setSearchFocus()) {
|
||||
_inner->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
bool Widget::showInternal(
|
||||
not_null<Window::SectionMemento*> memento,
|
||||
const Window::SectionShow ¶ms) {
|
||||
if (auto logMemento = dynamic_cast<SectionMemento*>(memento.get())) {
|
||||
if (logMemento->getChannel() == channel()) {
|
||||
restoreState(logMemento);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Widget::setInternalState(const QRect &geometry, not_null<SectionMemento*> memento) {
|
||||
setGeometry(geometry);
|
||||
Ui::SendPendingMoveResizeEvents(this);
|
||||
restoreState(memento);
|
||||
}
|
||||
|
||||
void Widget::setupShortcuts() {
|
||||
Shortcuts::Requests(
|
||||
) | rpl::filter([=] {
|
||||
return Ui::AppInFocus()
|
||||
&& Ui::InFocusChain(this)
|
||||
&& !controller()->isLayerShown()
|
||||
&& isActiveWindow();
|
||||
}) | rpl::on_next([=](not_null<Shortcuts::Request*> request) {
|
||||
using Command = Shortcuts::Command;
|
||||
request->check(Command::Search, 2) && request->handle([=] {
|
||||
_fixedBar->showSearch();
|
||||
return true;
|
||||
});
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void Widget::setupSwipeReply() {
|
||||
auto update = [=](Ui::Controls::SwipeContextData data) {
|
||||
if (data.translation > 0) {
|
||||
if (!_swipeBackData.callback) {
|
||||
_swipeBackData = Ui::Controls::SetupSwipeBack(
|
||||
this,
|
||||
[=]() -> std::pair<QColor, QColor> {
|
||||
auto context = _inner->preparePaintContext({});
|
||||
return {
|
||||
context.st->msgServiceBg()->c,
|
||||
context.st->msgServiceFg()->c,
|
||||
};
|
||||
});
|
||||
}
|
||||
_swipeBackData.callback(data);
|
||||
return;
|
||||
} else if (_swipeBackData.lifetime) {
|
||||
_swipeBackData = {};
|
||||
}
|
||||
};
|
||||
|
||||
auto init = [=](int, Qt::LayoutDirection direction) {
|
||||
if (direction == Qt::RightToLeft) {
|
||||
return Ui::Controls::DefaultSwipeBackHandlerFinishData([=] {
|
||||
controller()->showBackFromStack();
|
||||
});
|
||||
}
|
||||
return Ui::Controls::SwipeHandlerFinishData();
|
||||
};
|
||||
|
||||
Ui::Controls::SetupSwipeHandler({
|
||||
.widget = _inner.data(),
|
||||
.scroll = _scroll.data(),
|
||||
.update = std::move(update),
|
||||
.init = std::move(init),
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<Window::SectionMemento> Widget::createMemento() {
|
||||
auto result = std::make_shared<SectionMemento>(channel());
|
||||
saveState(result.get());
|
||||
return result;
|
||||
}
|
||||
|
||||
void Widget::saveState(not_null<SectionMemento*> memento) {
|
||||
memento->setScrollTop(_scroll->scrollTop());
|
||||
_inner->saveState(memento);
|
||||
}
|
||||
|
||||
void Widget::restoreState(not_null<SectionMemento*> memento) {
|
||||
_inner->restoreState(memento);
|
||||
auto scrollTop = memento->getScrollTop();
|
||||
_scroll->scrollToY(scrollTop);
|
||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||
}
|
||||
|
||||
void Widget::resizeEvent(QResizeEvent *e) {
|
||||
if (!width() || !height()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto contentWidth = width();
|
||||
|
||||
auto newScrollTop = _scroll->scrollTop() + topDelta();
|
||||
_fixedBar->resizeToWidth(contentWidth);
|
||||
_fixedBarShadow->resize(contentWidth, st::lineWidth);
|
||||
|
||||
auto bottom = height();
|
||||
auto scrollHeight = bottom - _fixedBar->height() - _whatIsThis->height();
|
||||
auto scrollSize = QSize(contentWidth, scrollHeight);
|
||||
if (_scroll->size() != scrollSize) {
|
||||
_scroll->resize(scrollSize);
|
||||
_inner->resizeToWidth(scrollSize.width(), _scroll->height());
|
||||
_inner->restoreScrollPosition();
|
||||
}
|
||||
|
||||
if (!_scroll->isHidden()) {
|
||||
if (topDelta()) {
|
||||
_scroll->scrollToY(newScrollTop);
|
||||
}
|
||||
auto scrollTop = _scroll->scrollTop();
|
||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||
}
|
||||
auto fullWidthButtonRect = myrtlrect(0, bottom - _whatIsThis->height(), contentWidth, _whatIsThis->height());
|
||||
_whatIsThis->setGeometry(fullWidthButtonRect);
|
||||
}
|
||||
|
||||
void Widget::paintEvent(QPaintEvent *e) {
|
||||
if (animatingShow()) {
|
||||
SectionWidget::paintEvent(e);
|
||||
return;
|
||||
} else if (controller()->contentOverlapped(this, e)) {
|
||||
return;
|
||||
}
|
||||
//if (hasPendingResizedItems()) {
|
||||
// updateListSize();
|
||||
//}
|
||||
|
||||
//auto ms = crl::now();
|
||||
//_historyDownShown.step(ms);
|
||||
|
||||
const auto clip = e->rect();
|
||||
SectionWidget::PaintBackground(controller(), _inner->theme(), this, clip);
|
||||
}
|
||||
|
||||
void Widget::onScroll() {
|
||||
int scrollTop = _scroll->scrollTop();
|
||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||
}
|
||||
|
||||
void Widget::showAnimatedHook(
|
||||
const Window::SectionSlideParams ¶ms) {
|
||||
_fixedBar->setAnimatingMode(true);
|
||||
if (params.withTopBarShadow) _fixedBarShadow->show();
|
||||
}
|
||||
|
||||
void Widget::showFinishedHook() {
|
||||
_fixedBar->setAnimatingMode(false);
|
||||
}
|
||||
|
||||
bool Widget::floatPlayerHandleWheelEvent(QEvent *e) {
|
||||
return _scroll->viewportEvent(e);
|
||||
}
|
||||
|
||||
QRect Widget::floatPlayerAvailableRect() {
|
||||
return mapToGlobal(_scroll->geometry());
|
||||
}
|
||||
|
||||
void Widget::applyFilter(FilterValue &&value) {
|
||||
_fixedBar->applyFilter(value);
|
||||
_inner->applyFilter(std::move(value));
|
||||
}
|
||||
|
||||
} // namespace AdminLog
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "window/section_widget.h"
|
||||
#include "window/section_memento.h"
|
||||
#include "history/admin_log/history_admin_log_item.h"
|
||||
#include "history/admin_log/history_admin_log_filter_value.h"
|
||||
#include "ui/controls/swipe_handler_data.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
namespace Ui {
|
||||
class ScrollArea;
|
||||
class PlainShadow;
|
||||
class FlatButton;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Profile {
|
||||
class BackButton;
|
||||
} // namespace Profile
|
||||
|
||||
namespace AdminLog {
|
||||
|
||||
class FixedBar;
|
||||
class InnerWidget;
|
||||
class SectionMemento;
|
||||
|
||||
class Widget final : public Window::SectionWidget {
|
||||
public:
|
||||
Widget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<ChannelData*> channel);
|
||||
|
||||
not_null<ChannelData*> channel() const;
|
||||
Dialogs::RowDescriptor activeChat() const override;
|
||||
|
||||
bool hasTopBarShadow() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms) override;
|
||||
|
||||
bool showInternal(
|
||||
not_null<Window::SectionMemento*> memento,
|
||||
const Window::SectionShow ¶ms) override;
|
||||
std::shared_ptr<Window::SectionMemento> createMemento() override;
|
||||
|
||||
void setInternalState(const QRect &geometry, not_null<SectionMemento*> memento);
|
||||
|
||||
// Float player interface.
|
||||
bool floatPlayerHandleWheelEvent(QEvent *e) override;
|
||||
QRect floatPlayerAvailableRect() override;
|
||||
|
||||
void applyFilter(FilterValue &&value);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void showAnimatedHook(
|
||||
const Window::SectionSlideParams ¶ms) override;
|
||||
void showFinishedHook() override;
|
||||
void doSetInnerFocus() override;
|
||||
|
||||
private:
|
||||
void showFilter();
|
||||
void onScroll();
|
||||
void updateAdaptiveLayout();
|
||||
void saveState(not_null<SectionMemento*> memento);
|
||||
void restoreState(not_null<SectionMemento*> memento);
|
||||
void setupShortcuts();
|
||||
void setupSwipeReply();
|
||||
|
||||
object_ptr<Ui::ScrollArea> _scroll;
|
||||
QPointer<InnerWidget> _inner;
|
||||
object_ptr<FixedBar> _fixedBar;
|
||||
object_ptr<Ui::PlainShadow> _fixedBarShadow;
|
||||
object_ptr<Ui::FlatButton> _whatIsThis;
|
||||
|
||||
Ui::Controls::SwipeBackResult _swipeBackData;
|
||||
|
||||
};
|
||||
|
||||
class SectionMemento : public Window::SectionMemento {
|
||||
public:
|
||||
using Element = HistoryView::Element;
|
||||
|
||||
SectionMemento(not_null<ChannelData*> channel) : _channel(channel) {
|
||||
}
|
||||
|
||||
object_ptr<Window::SectionWidget> createWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
Window::Column column,
|
||||
const QRect &geometry) override;
|
||||
|
||||
not_null<ChannelData*> getChannel() const {
|
||||
return _channel;
|
||||
}
|
||||
void setScrollTop(int scrollTop) {
|
||||
_scrollTop = scrollTop;
|
||||
}
|
||||
int getScrollTop() const {
|
||||
return _scrollTop;
|
||||
}
|
||||
|
||||
void setAdmins(std::vector<not_null<UserData*>> admins) {
|
||||
_admins = std::move(admins);
|
||||
}
|
||||
void setAdminsCanEdit(std::vector<not_null<UserData*>> admins) {
|
||||
_adminsCanEdit = std::move(admins);
|
||||
}
|
||||
std::vector<not_null<UserData*>> takeAdmins() {
|
||||
return std::move(_admins);
|
||||
}
|
||||
std::vector<not_null<UserData*>> takeAdminsCanEdit() {
|
||||
return std::move(_adminsCanEdit);
|
||||
}
|
||||
|
||||
void setItems(
|
||||
std::vector<OwnedItem> &&items,
|
||||
std::set<uint64> &&eventIds,
|
||||
bool upLoaded,
|
||||
bool downLoaded) {
|
||||
_items = std::move(items);
|
||||
_eventIds = std::move(eventIds);
|
||||
_upLoaded = upLoaded;
|
||||
_downLoaded = downLoaded;
|
||||
}
|
||||
void setFilter(FilterValue &&filter) {
|
||||
_filter = std::move(filter);
|
||||
}
|
||||
void setSearchQuery(QString &&query) {
|
||||
_searchQuery = std::move(query);
|
||||
}
|
||||
std::vector<OwnedItem> takeItems() {
|
||||
return std::move(_items);
|
||||
}
|
||||
std::set<uint64> takeEventIds() {
|
||||
return std::move(_eventIds);
|
||||
}
|
||||
bool upLoaded() const {
|
||||
return _upLoaded;
|
||||
}
|
||||
bool downLoaded() const {
|
||||
return _downLoaded;
|
||||
}
|
||||
FilterValue takeFilter() {
|
||||
return std::move(_filter);
|
||||
}
|
||||
QString takeSearchQuery() {
|
||||
return std::move(_searchQuery);
|
||||
}
|
||||
|
||||
private:
|
||||
not_null<ChannelData*> _channel;
|
||||
int _scrollTop = 0;
|
||||
std::vector<not_null<UserData*>> _admins;
|
||||
std::vector<not_null<UserData*>> _adminsCanEdit;
|
||||
std::vector<OwnedItem> _items;
|
||||
std::set<uint64> _eventIds;
|
||||
bool _upLoaded = false;
|
||||
bool _downLoaded = true;
|
||||
FilterValue _filter;
|
||||
QString _searchQuery;
|
||||
|
||||
};
|
||||
|
||||
} // namespace AdminLog
|
||||
Reference in New Issue
Block a user