Support deleting and reporting stories.

This commit is contained in:
John Preston 2023-06-22 19:29:11 +04:00
parent ebafb55b1b
commit e21c06f67c
19 changed files with 322 additions and 100 deletions

View File

@ -757,6 +757,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_background_apply2" = "Enjoy the view.";
"lng_background_apply_button" = "Apply For This Chat";
"lng_background_dimming" = "Background dimming";
"lng_background_sure_reset_default" = "Are you sure you want to reset the wallpaper?";
"lng_background_reset_default" = "Reset";
"lng_download_path_ask" = "Ask download path for each file";
"lng_download_path" = "Download path";
@ -1348,6 +1350,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_report_group_video_title" = "Report group video";
"lng_report_channel_photo_title" = "Report channel photo";
"lng_report_channel_video_title" = "Report channel video";
"lng_report_story" = "Report story";
"lng_report_please_select_messages" = "Please select messages to report.";
"lng_report_select_messages" = "Select messages";
"lng_report_messages_none" = "Select Messages";
@ -3822,6 +3825,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stories_reply_sent" = "Message Sent";
"lng_stories_hidden_to_contacts" = "Those stories are now shown only in your Contacts list.";
"lng_stories_shown_in_chats" = "Those stories are now shown in your Chats list.";
"lng_stories_delete_one_sure" = "Are you sure you want to delete this story?";
"lng_stories_delete_sure#one" = "Are you sure you want to delete {count} story?";
"lng_stories_delete_sure#other" = "Are you sure you want to delete {count} stories?";
"lng_stories_link_invalid" = "This link is broken or has expired.";

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_user.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/boxes/report_box.h"
@ -39,11 +40,15 @@ MTPreportReason ReasonToTL(const Ui::ReportReason &reason) {
} // namespace
void SendReport(
std::shared_ptr<Ui::Show> show,
not_null<PeerData*> peer,
Ui::ReportReason reason,
const QString &comment,
std::variant<v::null_t, MessageIdsList, not_null<PhotoData*>> data) {
std::shared_ptr<Ui::Show> show,
not_null<PeerData*> peer,
Ui::ReportReason reason,
const QString &comment,
std::variant<
v::null_t,
MessageIdsList,
not_null<PhotoData*>,
StoryId> data) {
auto done = [=] {
show->showToast(tr::lng_report_thanks(tr::now));
};
@ -72,6 +77,17 @@ void SendReport(
ReasonToTL(reason),
MTP_string(comment)
)).done(std::move(done)).send();
}, [&](StoryId id) {
const auto user = peer->asUser();
if (!user) {
return;
}
peer->session().api().request(MTPstories_Report(
user->inputUser,
MTP_vector<MTPint>(1, MTP_int(id)),
ReasonToTL(reason),
MTP_string(comment)
)).done(std::move(done)).send();
});
}

View File

@ -22,6 +22,10 @@ void SendReport(
not_null<PeerData*> peer,
Ui::ReportReason reason,
const QString &comment,
std::variant<v::null_t, MessageIdsList, not_null<PhotoData*>> data);
std::variant<
v::null_t,
MessageIdsList,
not_null<PhotoData*>,
StoryId> data);
} // namespace Api

View File

@ -282,9 +282,9 @@ void BackgroundBox::chosen(const Data::WallPaper &paper) {
close();
});
_controller->show(Ui::MakeConfirmBox({
.text = u"Are you sure you want to reset the wallpaper?"_q,
.text = tr::lng_background_sure_reset_default(),
.confirmed = reset,
.confirmText = u"Reset"_q,
.confirmText = tr::lng_background_reset_default(),
}));
} else {
closeBox();

View File

@ -14,12 +14,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/report_box.h"
#include "ui/layers/generic_box.h"
#include "window/window_session_controller.h"
#include "styles/style_chat_helpers.h"
namespace {
[[nodiscard]] object_ptr<Ui::BoxContent> Report(
not_null<PeerData*> peer,
std::variant<v::null_t, MessageIdsList, not_null<PhotoData*>> data) {
std::variant<
v::null_t,
MessageIdsList,
not_null<PhotoData*>,
StoryId> data,
const style::ReportBox *stOverride) {
const auto source = v::match(data, [](const MessageIdsList &ids) {
return Ui::ReportSource::Message;
}, [&](not_null<PhotoData*> photo) {
@ -34,15 +40,18 @@ namespace {
: (photo->hasVideo()
? Ui::ReportSource::ChannelVideo
: Ui::ReportSource::ChannelPhoto);
}, [&](StoryId id) {
return Ui::ReportSource::Story;
}, [](v::null_t) {
Unexpected("Bad source report.");
return Ui::ReportSource::Bot;
});
const auto st = stOverride ? stOverride : &st::defaultReportBox;
return Box([=](not_null<Ui::GenericBox*> box) {
const auto show = box->uiShow();
Ui::ReportReasonBox(box, source, [=](Ui::ReportReason reason) {
Ui::ReportReasonBox(box, *st, source, [=](Ui::ReportReason reason) {
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
Ui::ReportDetailsBox(box, [=](const QString &text) {
Ui::ReportDetailsBox(box, *st, [=](const QString &text) {
Api::SendReport(show, peer, reason, text, data);
show->hideLayer();
});
@ -56,13 +65,13 @@ namespace {
object_ptr<Ui::BoxContent> ReportItemsBox(
not_null<PeerData*> peer,
MessageIdsList ids) {
return Report(peer, ids);
return Report(peer, ids, nullptr);
}
object_ptr<Ui::BoxContent> ReportProfilePhotoBox(
not_null<PeerData*> peer,
not_null<PhotoData*> photo) {
return Report(peer, photo);
return Report(peer, photo, nullptr);
}
void ShowReportPeerBox(
@ -93,17 +102,20 @@ void ShowReportPeerBox(
if (reason == Ui::ReportReason::Fake
|| reason == Ui::ReportReason::Other) {
state->ids = {};
state->detailsBox = window->show(Box(Ui::ReportDetailsBox, send));
state->detailsBox = window->show(
Box(Ui::ReportDetailsBox, st::defaultReportBox, send));
return;
}
window->showChooseReportMessages(peer, reason, [=](
MessageIdsList ids) {
state->ids = std::move(ids);
state->detailsBox = window->show(Box(Ui::ReportDetailsBox, send));
state->detailsBox = window->show(
Box(Ui::ReportDetailsBox, st::defaultReportBox, send));
});
};
state->reasonBox = window->show(Box(
Ui::ReportReasonBox,
st::defaultReportBox,
(peer->isBroadcast()
? Ui::ReportSource::Channel
: peer->isUser()

View File

@ -206,6 +206,21 @@ ComposeControls {
premium: PremiumLimits;
}
ReportBox {
button: SettingsButton;
label: FlatLabel;
field: InputField;
spam: icon;
fake: icon;
violence: icon;
children: icon;
pornography: icon;
copyright: icon;
drugs: icon;
personal: icon;
other: icon;
}
WhoRead {
userpics: GroupCallUserpics;
photoLeft: pixels;
@ -1152,3 +1167,25 @@ moreChatsBarClose: IconButton(defaultIconButton) {
color: windowBgOver;
}
}
reportReasonTopSkip: 8px;
reportReasonButton: SettingsButton(defaultSettingsButton) {
style: boxTextStyle;
padding: margins(62px, 7px, 8px, 7px);
iconLeft: 22px;
}
defaultReportBox: ReportBox {
button: reportReasonButton;
label: boxLabel;
field: newGroupDescription;
spam: menuIconDelete;
fake: menuIconFake;
violence: menuIconViolence;
children: menuIconBlock;
pornography: menuIconPorn;
copyright: menuIconCopyright;
drugs: menuIconDrugs;
personal: menuIconPersonal;
other: menuIconReport;
}

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/data_stories.h"
#include "api/api_report.h"
#include "base/unixtime.h"
#include "api/api_text_entities.h"
#include "apiwrap.h"
@ -223,6 +224,22 @@ bool Story::closeFriends() const {
return _closeFriends;
}
bool Story::canDownload() const {
return _peer->isSelf();
}
bool Story::canShare() const {
return isPublic() && (pinned() || !expired());
}
bool Story::canDelete() const {
return _peer->isSelf();
}
bool Story::canReport() const {
return !_peer->isSelf();
}
bool Story::hasDirectLink() const {
if (!_isPublic || (!_pinned && expired())) {
return false;
@ -1479,7 +1496,38 @@ void Stories::savedLoadMore(PeerId peerId) {
saved.total = int(saved.ids.list.size());
_savedChanged.fire_copy(peerId);
}).send();
}
void Stories::deleteList(const std::vector<FullStoryId> &ids) {
auto list = QVector<MTPint>();
list.reserve(ids.size());
const auto selfId = session().userPeerId();
for (const auto &id : ids) {
if (id.peer == selfId) {
list.push_back(MTP_int(id.story));
}
}
if (!list.empty()) {
const auto api = &_owner->session().api();
api->request(MTPstories_DeleteStories(
MTP_vector<MTPint>(list)
)).done([=](const MTPVector<MTPint> &result) {
for (const auto &id : result.v) {
applyDeleted({ selfId, id.v });
}
}).send();
}
}
void Stories::report(
std::shared_ptr<Ui::Show> show,
FullStoryId id,
Ui::ReportReason reason,
QString text) {
if (const auto maybeStory = lookup(id)) {
const auto story = *maybeStory;
Api::SendReport(show, story->peer(), reason, text, story->id());
}
}
bool Stories::isQuitPrevent() {

View File

@ -23,6 +23,7 @@ class Session;
namespace Ui {
class Show;
enum class ReportReason;
} // namespace Ui
namespace Data {
@ -106,6 +107,11 @@ public:
void setCloseFriends(bool closeFriends);
[[nodiscard]] bool closeFriends() const;
[[nodiscard]] bool canDownload() const;
[[nodiscard]] bool canShare() const;
[[nodiscard]] bool canDelete() const;
[[nodiscard]] bool canReport() const;
[[nodiscard]] bool hasDirectLink() const;
[[nodiscard]] std::optional<QString> errorTextForForward(
not_null<Thread*> to) const;
@ -284,6 +290,13 @@ public:
[[nodiscard]] bool savedLoaded(PeerId peerId) const;
void savedLoadMore(PeerId peerId);
void deleteList(const std::vector<FullStoryId> &ids);
void report(
std::shared_ptr<Ui::Show> show,
FullStoryId id,
Ui::ReportReason reason,
QString text);
private:
struct Saved {
StoriesIds ids;

View File

@ -4009,7 +4009,8 @@ void HistoryWidget::reportSelectedMessages() {
const auto reason = _chooseForReport->reason;
const auto weak = Ui::MakeWeak(_list.data());
controller()->window().show(Box([=](not_null<Ui::GenericBox*> box) {
Ui::ReportDetailsBox(box, [=](const QString &text) {
const auto &st = st::defaultReportBox;
Ui::ReportDetailsBox(box, st, [=](const QString &text) {
if (weak) {
clearSelected();
controller()->clearChooseReportMessages();

View File

@ -885,10 +885,4 @@ shortInfoCover: ShortInfoCover {
}
}
reportReasonTopSkip: 8px;
reportReasonButton: SettingsButton(infoProfileButton) {
style: boxTextStyle;
padding: margins(62px, 7px, 8px, 7px);
}
permissionsExpandIcon: icon{{ "info/edit/expand_arrow_small", windowBoldFg }};

View File

@ -33,6 +33,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/stories/media_stories_share.h"
#include "media/stories/media_stories_view.h"
#include "media/audio/media_audio.h"
#include "ui/boxes/confirm_box.h"
#include "ui/boxes/report_box.h"
#include "ui/effects/emoji_fly_animation.h"
#include "ui/effects/message_sending_animation_common.h"
#include "ui/effects/reaction_fly_animation.h"
@ -493,6 +495,11 @@ void Controller::initLayout() {
});
}
Data::Story *Controller::story() const {
const auto maybeStory = _session->data().stories().lookup(_shown);
return maybeStory ? maybeStory->get() : nullptr;
}
not_null<Ui::RpWidget*> Controller::wrap() const {
return _wrap;
}
@ -995,25 +1002,6 @@ void Controller::setMenuShown(bool shown) {
}
}
bool Controller::canShare() const {
if (const auto maybeStory = _session->data().stories().lookup(_shown)) {
const auto story = *maybeStory;
const auto user = story->peer()->asUser();
return story->isPublic()
&& (story->pinned() || !story->expired())
&& (!user->username().isEmpty()
|| !user->hasPrivateForwardName());
}
return false;
}
bool Controller::canDownload() const {
if (const auto maybeStory = _session->data().stories().lookup(_shown)) {
return (*maybeStory)->peer()->isSelf();
}
return false;
}
void Controller::repaintSibling(not_null<Sibling*> sibling) {
if (sibling == _siblingLeft.get() || sibling == _siblingRight.get()) {
_delegate->storiesRepaint();
@ -1237,13 +1225,55 @@ void Controller::unfocusReply() {
_wrap->setFocus();
}
void Controller::share() {
void Controller::shareRequested() {
const auto show = _delegate->storiesShow();
if (auto box = PrepareShareBox(show, _shown)) {
show->show(std::move(box));
}
}
void Controller::deleteRequested() {
const auto story = this->story();
if (!story) {
return;
}
const auto id = story->fullId();
const auto owner = &story->owner();
const auto confirmed = [=](Fn<void()> close) {
owner->stories().deleteList({ id });
close();
};
uiShow()->show(Ui::MakeConfirmBox({
.text = tr::lng_stories_delete_one_sure(),
.confirmed = confirmed,
.confirmText = tr::lng_selected_delete(),
.labelStyle = &st::storiesBoxLabel,
}));
}
void Controller::reportRequested() {
const auto story = this->story();
if (!story) {
return;
}
const auto id = story->fullId();
const auto owner = &story->owner();
const auto confirmed = [=](Fn<void()> close) {
owner->stories().deleteList({ id });
close();
};
const auto show = uiShow();
const auto st = &st::storiesReportBox;
show->show(Box(Ui::ReportReasonBox, *st, Ui::ReportSource::Story, [=](
Ui::ReportReason reason) {
const auto done = [=](const QString &text) {
owner->stories().report(show, id, reason, text);
show->hideLayer();
};
show->showBox(Box(Ui::ReportDetailsBox, *st, done));
}));
}
rpl::lifetime &Controller::lifetime() {
return _lifetime;
}

View File

@ -96,6 +96,7 @@ public:
explicit Controller(not_null<Delegate*> delegate);
~Controller();
[[nodiscard]] Data::Story *story() const;
[[nodiscard]] not_null<Ui::RpWidget*> wrap() const;
[[nodiscard]] Layout layout() const;
[[nodiscard]] rpl::producer<Layout> layoutValue() const;
@ -123,9 +124,6 @@ public:
void contentPressed(bool pressed);
void setMenuShown(bool shown);
[[nodiscard]] bool canShare() const;
[[nodiscard]] bool canDownload() const;
void repaintSibling(not_null<Sibling*> sibling);
[[nodiscard]] SiblingView sibling(SiblingType type) const;
@ -133,7 +131,9 @@ public:
[[nodiscard]] rpl::producer<> moreViewsLoaded() const;
void unfocusReply();
void share();
void shareRequested();
void deleteRequested();
void reportRequested();
[[nodiscard]] rpl::lifetime &lifetime();

View File

@ -32,12 +32,8 @@ void View::ready() {
_controller->ready();
}
bool View::canShare() const {
return _controller->canShare();
}
bool View::canDownload() const {
return _controller->canDownload();
Data::Story *View::story() const {
return _controller->story();
}
QRect View::finalShownGeometry() const {
@ -83,8 +79,16 @@ void View::contentPressed(bool pressed) {
_controller->contentPressed(pressed);
}
void View::share() {
_controller->share();
void View::shareRequested() {
_controller->shareRequested();
}
void View::deleteRequested() {
_controller->deleteRequested();
}
void View::reportRequested() {
_controller->reportRequested();
}
SiblingView View::sibling(SiblingType type) const {

View File

@ -56,8 +56,7 @@ public:
void show(not_null<Data::Story*> story, Data::StoriesContext context);
void ready();
[[nodiscard]] bool canShare() const;
[[nodiscard]] bool canDownload() const;
[[nodiscard]] Data::Story *story() const;
[[nodiscard]] QRect finalShownGeometry() const;
[[nodiscard]] rpl::producer<QRect> finalShownGeometryValue() const;
[[nodiscard]] ContentLayout contentLayout() const;
@ -75,7 +74,10 @@ public:
[[nodiscard]] bool paused() const;
void togglePaused(bool paused);
void contentPressed(bool pressed);
void share();
void shareRequested();
void deleteRequested();
void reportRequested();
[[nodiscard]] rpl::lifetime &lifetime();

View File

@ -509,6 +509,9 @@ storiesPopupMenuWithIcons: PopupMenu(storiesPopupMenu) {
menu: storiesMenuWithIcons;
}
storiesBoxLabel: FlatLabel(boxLabel) {
textFg: groupCallMembersFg;
}
storiesAttachEmojiInner: IconButton(storiesAttach) {
icon: icon {{ "chat/input_smile_face", storiesComposeGrayIcon }};
iconOver: icon {{ "chat/input_smile_face", storiesComposeGrayIcon }};
@ -520,9 +523,7 @@ storiesAttachEmoji: EmojiButton(historyAttachEmoji) {
lineFgOver: storiesComposeGrayIcon;
}
storiesComposePremium: PremiumLimits(defaultPremiumLimits) {
boxLabel: FlatLabel(boxLabel) {
textFg: groupCallMembersFg;
}
boxLabel: storiesBoxLabel;
nonPremiumBg: storiesComposeBgOver;
nonPremiumFg: storiesComposeWhiteText;
}
@ -588,9 +589,7 @@ storiesEmojiPan: EmojiPan(defaultEmojiPan) {
}
search: storiesEmojiTabbedSearch;
removeSet: storiesRemoveSet;
boxLabel: FlatLabel(boxLabel) {
textFg: groupCallMembersFg;
}
boxLabel: storiesBoxLabel;
icons: ComposeIcons {
settings: icon {{ "emoji/emoji_settings", storiesComposeGrayIcon }};
@ -642,6 +641,15 @@ storiesEmojiPan: EmojiPan(defaultEmojiPan) {
}
autocompleteBottomSkip: 10px;
}
storiesBoxInputField: InputField(defaultComposeFilesField) {
textFg: storiesComposeWhiteText;
textBg: storiesComposeBg;
placeholderFg: storiesComposeGrayText;
placeholderFgActive: storiesComposeBlue;
borderFg: storiesComposeGrayText;
borderFgActive: storiesComposeBlue;
menu: storiesPopupMenu;
}
storiesComposeControls: ComposeControls(defaultComposeControls) {
bg: storiesComposeBg;
radius: storiesRadius;
@ -718,15 +726,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
iconOver: icon {{ "title_menu_dots", storiesComposeGrayIcon }};
ripple: storiesComposeRippleLight;
}
caption: InputField(defaultComposeFilesField) {
textFg: storiesComposeWhiteText;
textBg: storiesComposeBg;
placeholderFg: storiesComposeGrayText;
placeholderFgActive: storiesComposeBlue;
borderFg: storiesComposeGrayText;
borderFgActive: storiesComposeBlue;
menu: storiesPopupMenu;
}
caption: storiesBoxInputField;
emoji: EmojiButton(storiesAttachEmoji) {
inner: IconButton(storiesAttachEmojiInner) {
width: 30px;
@ -818,3 +818,26 @@ storiesShortInfoBox: ShortInfoBox(shortInfoBox) {
palette: mediaviewTextPalette;
}
}
storiesReportBox: ReportBox(defaultReportBox) {
button: SettingsButton(reportReasonButton) {
textFg: storiesComposeWhiteText;
textFgOver: storiesComposeWhiteText;
textBg: storiesComposeBg;
textBgOver: storiesComposeBgOver;
ripple: storiesComposeRipple;
}
label: storiesBoxLabel;
field: InputField(storiesBoxInputField) {
textMargins: margins(1px, 26px, 1px, 4px);
heightMax: 116px;
}
spam: icon {{ "menu/delete", storiesComposeWhiteText }};
fake: icon {{ "menu/fake", storiesComposeWhiteText }};
violence: icon {{ "menu/violence", storiesComposeWhiteText }};
children: icon {{ "menu/block", storiesComposeWhiteText }};
pornography: icon {{ "menu/porn", storiesComposeWhiteText }};
copyright: icon {{ "menu/copyright", storiesComposeWhiteText }};
drugs: icon {{ "menu/drugs", storiesComposeWhiteText }};
personal: icon {{ "menu/personal", storiesComposeWhiteText }};
other: icon {{ "menu/report", storiesComposeWhiteText }};
}

View File

@ -970,7 +970,8 @@ QSize OverlayWidget::flipSizeByRotation(QSize size) const {
}
bool OverlayWidget::hasCopyMediaRestriction() const {
return (_stories && !_stories->canDownload())
const auto story = _stories ? _stories->story() : nullptr;
return (story && !story->canDownload())
|| (_history && !_history->peer->allowsForwarding())
|| (_message && _message->forbidsSaving());
}
@ -1223,12 +1224,13 @@ void OverlayWidget::updateControls() {
updateThemePreviewGeometry();
const auto story = _stories ? _stories->story() : nullptr;
const auto overRect = QRect(
QPoint(),
QSize(st::mediaviewIconOver, st::mediaviewIconOver));
_saveVisible = contentCanBeSaved();
_shareVisible = _stories && _stories->canShare();
_rotateVisible = !_themePreviewShown && !_stories;
_shareVisible = story && story->canShare();
_rotateVisible = !_themePreviewShown && !story;
const auto navRect = [&](int i) {
return QRect(width() - st::mediaviewIconSize.width() * i,
height() - st::mediaviewIconSize.height(),
@ -1364,7 +1366,8 @@ void OverlayWidget::refreshCaptionGeometry() {
}
void OverlayWidget::fillContextMenuActions(const MenuCallback &addAction) {
if (_document && _document->loading()) {
const auto story = _stories ? _stories->story() : nullptr;
if (!story && _document && _document->loading()) {
addAction(
tr::lng_cancel(tr::now),
[=] { saveCancel(); },
@ -1376,7 +1379,9 @@ void OverlayWidget::fillContextMenuActions(const MenuCallback &addAction) {
[=] { toMessage(); },
&st::mediaMenuIconShowInChat);
}
if (_document && !_document->filepath(true).isEmpty()) {
if ((!story || story->canDownload())
&& _document
&& !_document->filepath(true).isEmpty()) {
const auto text = Platform::IsMac()
? tr::lng_context_show_in_finder(tr::now)
: tr::lng_context_show_in_folder(tr::now);
@ -1406,8 +1411,15 @@ void OverlayWidget::fillContextMenuActions(const MenuCallback &addAction) {
[=] { forwardMedia(); },
&st::mediaMenuIconForward);
}
if (story && story->canShare()) {
addAction(tr::lng_mediaview_forward(tr::now), [=] {
_stories->shareRequested();
}, &st::mediaMenuIconForward);
}
const auto canDelete = [&] {
if (_message && _message->canDelete()) {
if (story && story->canDelete()) {
return true;
} else if (_message && _message->canDelete()) {
return true;
} else if (!_message
&& _photo
@ -1527,6 +1539,11 @@ void OverlayWidget::fillContextMenuActions(const MenuCallback &addAction) {
}
}, &st::mediaMenuIconReport);
}();
if (story && story->canReport()) {
addAction(tr::lng_profile_report(tr::now), [=] {
_stories->reportRequested();
}, &st::mediaMenuIconReport);
}
}
auto OverlayWidget::computeOverviewType() const
@ -2433,7 +2450,10 @@ void OverlayWidget::forwardMedia() {
}
void OverlayWidget::deleteMedia() {
if (!_session) {
if (_stories) {
_stories->deleteRequested();
return;
} else if (!_session) {
return;
}
@ -5521,7 +5541,7 @@ void OverlayWidget::handleMouseRelease(
} else if (_over == Over::Save && _down == Over::Save) {
downloadMedia();
} else if (_over == Over::Share && _down == Over::Share && _stories) {
_stories->share();
_stories->shareRequested();
} else if (_over == Over::Rotate && _down == Over::Rotate) {
playbackControlsRotate();
} else if (_over == Over::Icon && _down == Over::Icon) {

View File

@ -2102,3 +2102,4 @@ stories.incrementStoryViews#22126127 user_id:InputUser id:Vector<int> = Bool;
stories.getStoryViewsList#4b3b5e97 id:int offset_date:int offset_id:long limit:int = stories.StoryViewsList;
stories.getStoriesViews#9a75d6a6 id:Vector<int> = stories.StoryViews;
stories.exportStoryLink#16e443ce user_id:InputUser id:int = ExportedStoryLink;
stories.report#c95be06a user_id:InputUser id:Vector<int> reason:ReportReason message:string = Bool;

View File

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h"
#include "ui/toast/toast.h"
#include "info/profile/info_profile_icon.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_profile.h"
@ -32,6 +33,7 @@ using Reason = ReportReason;
void ReportReasonBox(
not_null<GenericBox*> box,
const style::ReportBox &st,
ReportSource source,
Fn<void(Reason)> done) {
box->setTitle([&] {
@ -50,28 +52,27 @@ void ReportReasonBox(
return tr::lng_report_channel_photo_title();
case Source::ChannelVideo:
return tr::lng_report_channel_video_title();
case Source::Story:
return tr::lng_report_story();
}
Unexpected("'source' in ReportReasonBox.");
}());
const auto isProfileSource = (source == Source::ProfilePhoto)
|| (source == Source::ProfileVideo);
auto margin = style::margins{ 0, st::reportReasonTopSkip, 0, 0 };
const auto add = [&](
Reason reason,
tr::phrase<> text,
const style::icon &icon) {
const auto &st = st::reportReasonButton;
const auto layout = box->verticalLayout();
const auto button = layout->add(
object_ptr<Ui::SettingsButton>(layout.get(), text(), st),
object_ptr<Ui::SettingsButton>(layout.get(), text(), st.button),
margin);
margin = {};
button->setClickedCallback([=] {
done(reason);
});
const auto height = st.padding.top()
+ st.height
+ st.padding.bottom();
const auto height = st.button.padding.top()
+ st.button.height
+ st.button.padding.bottom();
object_ptr<Info::Profile::FloatingIcon>(
button,
icon,
@ -80,49 +81,52 @@ void ReportReasonBox(
(height - icon.height()) / 2,
});
};
add(Reason::Spam, tr::lng_report_reason_spam, st::menuIconDelete);
if (source != Source::Message && !isProfileSource) {
add(Reason::Fake, tr::lng_report_reason_fake, st::menuIconFake);
add(Reason::Spam, tr::lng_report_reason_spam, st.spam);
if (source == Source::Channel
|| source == Source::Group
|| source == Source::Bot) {
add(Reason::Fake, tr::lng_report_reason_fake, st.fake);
}
add(
Reason::Violence,
tr::lng_report_reason_violence,
st::menuIconViolence);
st.violence);
add(
Reason::ChildAbuse,
tr::lng_report_reason_child_abuse,
st::menuIconBlock);
st.children);
add(
Reason::Pornography,
tr::lng_report_reason_pornography,
st::menuIconPorn);
st.pornography);
add(
Reason::Copyright,
tr::lng_report_reason_copyright,
st::menuIconCopyright);
if (source == Source::Message) {
st.copyright);
if (source == Source::Message || source == Source::Story) {
add(
Reason::IllegalDrugs,
tr::lng_report_reason_illegal_drugs,
st::menuIconDrugs);
st.drugs);
add(
Reason::PersonalDetails,
tr::lng_report_reason_personal_details,
st::menuIconPersonal);
st.personal);
}
add(Reason::Other, tr::lng_report_reason_other, st::menuIconReport);
add(Reason::Other, tr::lng_report_reason_other, st.other);
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}
void ReportDetailsBox(
not_null<GenericBox*> box,
const style::ReportBox &st,
Fn<void(QString)> done) {
box->addRow(
object_ptr<FlatLabel>(
box, // #TODO reports
tr::lng_report_details_about(),
st::boxLabel),
st.label),
{
st::boxRowPadding.left(),
st::boxPadding.top(),
@ -131,7 +135,7 @@ void ReportDetailsBox(
const auto details = box->addRow(
object_ptr<InputField>(
box,
st::newGroupDescription,
st.field,
InputField::Mode::MultiLine,
tr::lng_report_details(),
QString()));

View File

@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace style {
struct ReportBox;
} // namespace style
namespace Ui {
class GenericBox;
@ -22,6 +26,7 @@ enum class ReportSource {
GroupVideo,
ChannelPhoto,
ChannelVideo,
Story,
};
enum class ReportReason {
@ -38,11 +43,13 @@ enum class ReportReason {
void ReportReasonBox(
not_null<GenericBox*> box,
const style::ReportBox &st,
ReportSource source,
Fn<void(ReportReason)> done);
void ReportDetailsBox(
not_null<GenericBox*> box,
const style::ReportBox &st,
Fn<void(QString)> done);
} // namespace Ui