Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c37b08ac8b | ||
|
|
c52a5927e5 | ||
|
|
edcfac8da3 | ||
|
|
a994c9f017 | ||
|
|
66e6bf8217 | ||
|
|
4a4cc766c2 | ||
|
|
31cd841b75 | ||
|
|
1710890886 | ||
|
|
16f616c5e0 | ||
|
|
7600c9bb2f | ||
|
|
100a44daef | ||
|
|
54305fafde | ||
|
|
d172d3d7db | ||
|
|
cee593c423 | ||
|
|
43adbb1cb1 | ||
|
|
e96731be11 | ||
|
|
6ea062462f | ||
|
|
1bc8d6fb18 | ||
|
|
73d00a4caf | ||
|
|
a23561c380 | ||
|
|
bb75a6a31b | ||
|
|
ce79c1f0c4 | ||
|
|
3cdb82a0bf | ||
|
|
d2f928f0c3 | ||
|
|
3cc0110464 | ||
|
|
df533f2efe | ||
|
|
2529bd3f44 | ||
|
|
a5c12065af | ||
|
|
101e795af8 | ||
|
|
8faa65fdf3 | ||
|
|
644881bd3e | ||
|
|
efa1b2dcbc | ||
|
|
92a9832337 | ||
|
|
8f3456cd6c | ||
|
|
e67192cdf0 | ||
|
|
9f2683a35b | ||
|
|
0a7e25e45a | ||
|
|
643a034aae | ||
|
|
1c5a3aef54 | ||
|
|
bfe47a1ba2 | ||
|
|
acd76fc97b | ||
|
|
78fedce2d5 | ||
|
|
5261e962e2 | ||
|
|
e4bfd562b5 | ||
|
|
d289bbdc5e | ||
|
|
2e9e3b3751 | ||
|
|
af0a2f182c | ||
|
|
e3ac84a849 | ||
|
|
6dce8dfa20 | ||
|
|
eef1da56c8 | ||
|
|
e37866d0b9 | ||
|
|
1ed7d482ab | ||
|
|
f1a7db780e | ||
|
|
8591fae031 | ||
|
|
18b9bba21c | ||
|
|
580e15dc21 | ||
|
|
bf4fc2596a | ||
|
|
9a4d2bc8f9 | ||
|
|
62a2277f43 | ||
|
|
d11885d48c | ||
|
|
c8cec18ad3 | ||
|
|
86105403bf | ||
|
|
41288f5ddb | ||
|
|
9cc1a020f3 | ||
|
|
68f35e98e0 | ||
|
|
b6c9a1d655 | ||
|
|
9b35fa29b8 | ||
|
|
53272d951b |
11
.github/workflows/docker.yml
vendored
@@ -15,6 +15,9 @@ jobs:
|
||||
name: Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
IMAGE_TAG: ghcr.io/${{ github.repository }}/centos_env:latest
|
||||
|
||||
steps:
|
||||
- name: Clone.
|
||||
uses: actions/checkout@v2
|
||||
@@ -22,4 +25,10 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Docker image build.
|
||||
run: docker build -t telegram_desktop Telegram/build/docker/centos_env
|
||||
run: docker build -t $IMAGE_TAG --build-arg DEBUG= Telegram/build/docker/centos_env
|
||||
|
||||
- name: Push the Docker image.
|
||||
if: ${{ github.ref_name == github.event.repository.default_branch }}
|
||||
run: |
|
||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
|
||||
docker push $IMAGE_TAG
|
||||
|
||||
2
.github/workflows/linux.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
name: CentOS 7
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: docker.pkg.github.com/telegramdesktop/tdesktop/centos_env
|
||||
image: ghcr.io/${{ github.repository }}/centos_env
|
||||
credentials:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -137,6 +137,8 @@ PRIVATE
|
||||
api/api_peer_photo.h
|
||||
api/api_polls.cpp
|
||||
api/api_polls.h
|
||||
api/api_report.cpp
|
||||
api/api_report.h
|
||||
api/api_ringtones.cpp
|
||||
api/api_ringtones.h
|
||||
api/api_self_destruct.cpp
|
||||
@@ -186,8 +188,6 @@ PRIVATE
|
||||
boxes/peers/edit_peer_invite_link.h
|
||||
boxes/peers/edit_peer_invite_links.cpp
|
||||
boxes/peers/edit_peer_invite_links.h
|
||||
boxes/peers/edit_peer_history_visibility_box.cpp
|
||||
boxes/peers/edit_peer_history_visibility_box.h
|
||||
boxes/peers/edit_peer_permissions_box.cpp
|
||||
boxes/peers/edit_peer_permissions_box.h
|
||||
boxes/peers/edit_peer_reactions.cpp
|
||||
@@ -258,6 +258,8 @@ PRIVATE
|
||||
boxes/pin_messages_box.h
|
||||
boxes/reactions_settings_box.cpp
|
||||
boxes/reactions_settings_box.h
|
||||
boxes/report_messages_box.cpp
|
||||
boxes/report_messages_box.h
|
||||
boxes/ringtones_box.cpp
|
||||
boxes/ringtones_box.h
|
||||
boxes/self_destruction_box.cpp
|
||||
|
||||
BIN
Telegram/Resources/icons/info/edit/channel_manage_signature.png
Normal file
|
After Width: | Height: | Size: 503 B |
|
After Width: | Height: | Size: 901 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 477 B After Width: | Height: | Size: 432 B |
|
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 757 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 957 B After Width: | Height: | Size: 515 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 989 B |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 648 B After Width: | Height: | Size: 583 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1023 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 734 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 989 B After Width: | Height: | Size: 509 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 891 B |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/info/edit/group_manage_type.png
Normal file
|
After Width: | Height: | Size: 494 B |
BIN
Telegram/Resources/icons/info/edit/group_manage_type@2x.png
Normal file
|
After Width: | Height: | Size: 925 B |
BIN
Telegram/Resources/icons/info/edit/group_manage_type@3x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 650 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -1141,6 +1141,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_report_group_title" = "Report group";
|
||||
"lng_report_bot_title" = "Report bot";
|
||||
"lng_report_message_title" = "Report message";
|
||||
"lng_report_profile_photo_title" = "Report profile photo";
|
||||
"lng_report_profile_video_title" = "Report profile video";
|
||||
"lng_report_please_select_messages" = "Please select messages to report.";
|
||||
"lng_report_select_messages" = "Select messages";
|
||||
"lng_report_messages_none" = "Select Messages";
|
||||
@@ -1974,7 +1976,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_try_other_contact" = "Try someone else";
|
||||
"lng_create_group_link" = "Link";
|
||||
"lng_create_group_invite_link" = "Invite link";
|
||||
"lng_create_group_description" = "Description (optional)";
|
||||
"lng_create_group_description" = "Add description...";
|
||||
|
||||
"lng_drag_images_here" = "Drop images here";
|
||||
"lng_drag_photos_here" = "Drop photos here";
|
||||
@@ -2053,6 +2055,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_mediaview_yesterday" = "yesterday at {time}";
|
||||
"lng_mediaview_date_time" = "{date} at {time}";
|
||||
"lng_mediaview_set_userpic" = "Set as Main";
|
||||
"lng_mediaview_report_profile_photo" = "Report";
|
||||
|
||||
"lng_mediaview_saved_to" = "Image was saved to your {downloads} folder";
|
||||
"lng_mediaview_downloads" = "Downloads";
|
||||
@@ -2145,6 +2148,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_payments_webview_install_webkit" = "Please install WebKitGTK (webkit2gtk-5.0/webkit2gtk-4.1/webkit2gtk-4.0) using your package manager.";
|
||||
"lng_payments_webview_switch_mutter" = "Qt's window embedding doesn't work well with Mutter window manager. Please switch to another window manager or desktop environment.";
|
||||
"lng_payments_webview_switch_wayland" = "There is no way to embed WebView window on Wayland. Please switch to X11.";
|
||||
"lng_payments_webview_update_windows" = "Please update your system to Windows 8.1 or later.";
|
||||
"lng_payments_sure_close" = "Are you sure you want to close this payment form? The changes you made will be lost.";
|
||||
"lng_payments_receipt_label" = "Receipt";
|
||||
"lng_payments_receipt_label_test" = "Test receipt";
|
||||
@@ -2657,7 +2661,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_pinned_message" = "{from} pinned this message:";
|
||||
"lng_admin_log_unpinned_message" = "{from} unpinned this message";
|
||||
"lng_admin_log_edited_caption" = "{from} edited caption:";
|
||||
"lng_admin_log_removed_caption" = "{from} removed caption";
|
||||
"lng_admin_log_edited_media" = "{from} edited media:";
|
||||
"lng_admin_log_edited_media_and_caption" = "{from} edited media and caption:";
|
||||
"lng_admin_log_edited_media_and_removed_caption" = "{from} edited media and removed caption:";
|
||||
"lng_admin_log_removed_caption" = "{from} removed caption:";
|
||||
"lng_admin_log_previous_caption" = "Original caption";
|
||||
"lng_admin_log_edited_message" = "{from} edited this message:";
|
||||
"lng_admin_log_previous_message" = "Original message";
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="3.7.0.0" />
|
||||
Version="3.7.2.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,7,0,0
|
||||
PRODUCTVERSION 3,7,0,0
|
||||
FILEVERSION 3,7,2,0
|
||||
PRODUCTVERSION 3,7,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "3.7.0.0"
|
||||
VALUE "FileVersion", "3.7.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.7.0.0"
|
||||
VALUE "ProductVersion", "3.7.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,7,0,0
|
||||
PRODUCTVERSION 3,7,0,0
|
||||
FILEVERSION 3,7,2,0
|
||||
PRODUCTVERSION 3,7,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "3.7.0.0"
|
||||
VALUE "FileVersion", "3.7.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.7.0.0"
|
||||
VALUE "ProductVersion", "3.7.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -17,10 +17,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
namespace {
|
||||
|
||||
MessageIdsList HistoryItemsFromTL(
|
||||
[[nodiscard]] MessageIdsList HistoryItemsFromTL(
|
||||
not_null<Data::Session*> data,
|
||||
const QVector<MTPMessage> &messages) {
|
||||
auto result = MessageIdsList();
|
||||
@@ -45,8 +44,12 @@ MessageIdsList HistoryItemsFromTL(
|
||||
} // namespace
|
||||
|
||||
MessagesSearch::MessagesSearch(not_null<History*> history)
|
||||
: _history(history)
|
||||
, _api(&history->session().mtp()) {
|
||||
: _history(history) {
|
||||
}
|
||||
|
||||
MessagesSearch::~MessagesSearch() {
|
||||
_history->owner().histories().cancelRequest(
|
||||
base::take(_searchInHistoryRequest));
|
||||
}
|
||||
|
||||
void MessagesSearch::searchMessages(const QString &query, PeerData *from) {
|
||||
@@ -78,7 +81,7 @@ void MessagesSearch::searchRequest() {
|
||||
const auto flags = _from
|
||||
? MTP_flags(MTPmessages_Search::Flag::f_from_id)
|
||||
: MTP_flags(0);
|
||||
_requestId = _api.request(MTPmessages_Search(
|
||||
_requestId = _history->session().api().request(MTPmessages_Search(
|
||||
flags,
|
||||
_history->peer->input,
|
||||
MTP_string(_query),
|
||||
@@ -102,10 +105,11 @@ void MessagesSearch::searchRequest() {
|
||||
}).fail([=](const MTP::Error &error, mtpRequestId id) {
|
||||
_searchInHistoryRequest = 0;
|
||||
|
||||
if (_requestId == id) {
|
||||
_requestId = 0;
|
||||
}
|
||||
if (error.type() == u"SEARCH_QUERY_EMPTY"_q) {
|
||||
_messagesFounds.fire({ 0, MessageIdsList(), nextToken });
|
||||
} else if (_requestId == id) {
|
||||
_requestId = 0;
|
||||
}
|
||||
|
||||
finish();
|
||||
|
||||
@@ -7,8 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class HistoryItem;
|
||||
class History;
|
||||
class PeerData;
|
||||
@@ -24,6 +22,7 @@ struct FoundMessages {
|
||||
class MessagesSearch final {
|
||||
public:
|
||||
explicit MessagesSearch(not_null<History*> history);
|
||||
~MessagesSearch();
|
||||
|
||||
void searchMessages(const QString &query, PeerData *from);
|
||||
void searchMore();
|
||||
@@ -39,7 +38,6 @@ private:
|
||||
const QString &nextToken);
|
||||
|
||||
const not_null<History*> _history;
|
||||
MTP::Sender _api;
|
||||
|
||||
base::flat_map<QString, TLMessages> _cacheOfStartByToken;
|
||||
|
||||
|
||||
@@ -18,11 +18,10 @@ bool MessagesSearchMerged::RequestCompare::operator()(
|
||||
}
|
||||
|
||||
MessagesSearchMerged::MessagesSearchMerged(not_null<History*> history)
|
||||
: _apiSearch(history)
|
||||
, _migratedSearch(history->migrateFrom()
|
||||
? std::make_optional<MessagesSearch>(history->migrateFrom())
|
||||
: std::nullopt) {
|
||||
|
||||
: _apiSearch(history) {
|
||||
if (const auto migrated = history->migrateFrom()) {
|
||||
_migratedSearch.emplace(migrated);
|
||||
}
|
||||
const auto checkWaitingForTotal = [=] {
|
||||
if (_waitingForTotal) {
|
||||
if (_concatedFound.total >= 0 && _migratedFirstFound.total >= 0) {
|
||||
|
||||
78
Telegram/SourceFiles/api/api_report.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
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 "api/api_report.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/boxes/report_box.h"
|
||||
#include "ui/toast/toast.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
namespace {
|
||||
|
||||
MTPreportReason ReasonToTL(const Ui::ReportReason &reason) {
|
||||
using Reason = Ui::ReportReason;
|
||||
switch (reason) {
|
||||
case Reason::Spam: return MTP_inputReportReasonSpam();
|
||||
case Reason::Fake: return MTP_inputReportReasonFake();
|
||||
case Reason::Violence: return MTP_inputReportReasonViolence();
|
||||
case Reason::ChildAbuse: return MTP_inputReportReasonChildAbuse();
|
||||
case Reason::Pornography: return MTP_inputReportReasonPornography();
|
||||
case Reason::Copyright: return MTP_inputReportReasonCopyright();
|
||||
case Reason::IllegalDrugs: return MTP_inputReportReasonIllegalDrugs();
|
||||
case Reason::PersonalDetails:
|
||||
return MTP_inputReportReasonPersonalDetails();
|
||||
case Reason::Other: return MTP_inputReportReasonOther();
|
||||
}
|
||||
Unexpected("Bad reason group value.");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SendReport(
|
||||
not_null<QWidget*> toastParent,
|
||||
not_null<PeerData*> peer,
|
||||
Ui::ReportReason reason,
|
||||
const QString &comment,
|
||||
std::variant<v::null_t, MessageIdsList, not_null<PhotoData*>> data) {
|
||||
auto done = [=] {
|
||||
Ui::Toast::Show(toastParent, tr::lng_report_thanks(tr::now));
|
||||
};
|
||||
v::match(data, [&](v::null_t) {
|
||||
peer->session().api().request(MTPaccount_ReportPeer(
|
||||
peer->input,
|
||||
ReasonToTL(reason),
|
||||
MTP_string(comment)
|
||||
)).done(std::move(done)).send();
|
||||
}, [&](const MessageIdsList &ids) {
|
||||
auto apiIds = QVector<MTPint>();
|
||||
apiIds.reserve(ids.size());
|
||||
for (const auto &fullId : ids) {
|
||||
apiIds.push_back(MTP_int(fullId.msg));
|
||||
}
|
||||
peer->session().api().request(MTPmessages_Report(
|
||||
peer->input,
|
||||
MTP_vector<MTPint>(apiIds),
|
||||
ReasonToTL(reason),
|
||||
MTP_string(comment)
|
||||
)).done(std::move(done)).send();
|
||||
}, [&](not_null<PhotoData*> photo) {
|
||||
peer->session().api().request(MTPaccount_ReportProfilePhoto(
|
||||
peer->input,
|
||||
photo->mtpInput(),
|
||||
ReasonToTL(reason),
|
||||
MTP_string(comment)
|
||||
)).done(std::move(done)).send();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
26
Telegram/SourceFiles/api/api_report.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
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 PeerData;
|
||||
class PhotoData;
|
||||
|
||||
namespace Ui {
|
||||
enum class ReportReason;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Api {
|
||||
|
||||
void SendReport(
|
||||
not_null<QWidget*> toastParent,
|
||||
not_null<PeerData*> peer,
|
||||
Ui::ReportReason reason,
|
||||
const QString &comment,
|
||||
std::variant<v::null_t, MessageIdsList, not_null<PhotoData*>> data);
|
||||
|
||||
} // namespace Api
|
||||
@@ -20,10 +20,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/boxes/calendar_box.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "settings/settings_privacy_security.h"
|
||||
#include "ui/boxes/choose_date_time.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/passcode_box.h"
|
||||
#include "boxes/peers/add_bot_to_chat_box.h"
|
||||
@@ -510,7 +510,8 @@ not_null<Ui::SlideWrap<Ui::RpWidget>*> EditAdminBox::setupTransferButton(
|
||||
: tr::lng_rights_transfer_channel)(),
|
||||
rpl::single(QString()),
|
||||
[=] { transferOwnership(); },
|
||||
st::peerPermissionsButton));
|
||||
st::peerPermissionsButton,
|
||||
{}));
|
||||
|
||||
return wrap;
|
||||
}
|
||||
@@ -783,35 +784,33 @@ ChatRestrictionsInfo EditRestrictedBox::defaultRights() const {
|
||||
}
|
||||
|
||||
void EditRestrictedBox::showRestrictUntil() {
|
||||
auto tomorrow = QDate::currentDate().addDays(1);
|
||||
auto highlighted = isUntilForever()
|
||||
? tomorrow
|
||||
: base::unixtime::parse(getRealUntilValue()).date();
|
||||
auto month = highlighted;
|
||||
auto box = Box<Ui::CalendarBox>(Ui::CalendarBoxArgs{
|
||||
.month = month,
|
||||
.highlighted = highlighted,
|
||||
.callback = [=](const QDate &date) {
|
||||
setRestrictUntil(
|
||||
static_cast<int>(date.startOfDay().toSecsSinceEpoch()));
|
||||
},
|
||||
.finalize = [=](not_null<Ui::CalendarBox*> box) {
|
||||
box->addLeftButton(
|
||||
tr::lng_rights_chat_banned_forever(),
|
||||
[=] { setRestrictUntil(0); });
|
||||
},
|
||||
.minDate = tomorrow,
|
||||
.maxDate = QDate::currentDate().addDays(kMaxRestrictDelayDays),
|
||||
});
|
||||
_restrictUntilBox = Ui::MakeWeak(box.data());
|
||||
_show.showBox(std::move(box));
|
||||
_show.showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
const auto save = [=](TimeId result) {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
setRestrictUntil(result);
|
||||
box->closeBox();
|
||||
};
|
||||
const auto now = base::unixtime::now();
|
||||
const auto time = isUntilForever()
|
||||
? (now + kSecondsInDay)
|
||||
: getRealUntilValue();
|
||||
ChooseDateTimeBox(box, {
|
||||
.title = tr::lng_rights_chat_banned_until_header(),
|
||||
.submit = tr::lng_settings_save(),
|
||||
.done = save,
|
||||
.min = [=] { return now; },
|
||||
.time = time,
|
||||
.max = [=] {
|
||||
return now + kSecondsInDay * kMaxRestrictDelayDays;
|
||||
},
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
void EditRestrictedBox::setRestrictUntil(TimeId until) {
|
||||
_until = until;
|
||||
if (_restrictUntilBox) {
|
||||
_restrictUntilBox->closeBox();
|
||||
}
|
||||
_untilVariants.clear();
|
||||
createUntilGroup();
|
||||
createUntilVariants();
|
||||
@@ -861,8 +860,7 @@ void EditRestrictedBox::createUntilVariants() {
|
||||
tr::lng_rights_chat_banned_custom_date(
|
||||
tr::now,
|
||||
lt_date,
|
||||
langDayOfMonthFull(
|
||||
base::unixtime::parse(until).date())));
|
||||
langDateTime(base::unixtime::parse(until))));
|
||||
}
|
||||
};
|
||||
auto addCurrentVariant = [&](TimeId from, TimeId to) {
|
||||
|
||||
@@ -17,7 +17,6 @@ class LinkButton;
|
||||
class Checkbox;
|
||||
class Radiobutton;
|
||||
class RadiobuttonGroup;
|
||||
class CalendarBox;
|
||||
class VerticalLayout;
|
||||
template <typename Widget>
|
||||
class SlideWrap;
|
||||
@@ -176,7 +175,6 @@ private:
|
||||
|
||||
std::shared_ptr<Ui::RadiobuttonGroup> _untilGroup;
|
||||
std::vector<base::unique_qptr<Ui::Radiobutton>> _untilVariants;
|
||||
QPointer<Ui::CalendarBox> _restrictUntilBox;
|
||||
|
||||
static constexpr auto kUntilOneDay = -1;
|
||||
static constexpr auto kUntilOneWeek = -2;
|
||||
|
||||
@@ -7,125 +7,56 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/peers/edit_peer_history_visibility_box.h"
|
||||
|
||||
#include "boxes/peers/edit_peer_permissions_box.h"
|
||||
#include "boxes/peers/edit_participants_box.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_info.h"
|
||||
|
||||
namespace {
|
||||
void EditPeerHistoryVisibilityBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
bool isLegacy,
|
||||
Fn<void(HistoryVisibility)> savedCallback,
|
||||
HistoryVisibility historyVisibilitySavedValue) {
|
||||
const auto historyVisibility = std::make_shared<
|
||||
Ui::RadioenumGroup<HistoryVisibility>
|
||||
>(historyVisibilitySavedValue);
|
||||
|
||||
void AddRadioButton(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
HistoryVisibility value,
|
||||
const QString &groupText,
|
||||
rpl::producer<QString> groupAbout,
|
||||
std::shared_ptr<Ui::RadioenumGroup<HistoryVisibility>> historyVisibility) {
|
||||
container->add(object_ptr<Ui::FixedHeightWidget>(
|
||||
container,
|
||||
st::editPeerHistoryVisibilityTopSkip));
|
||||
container->add(object_ptr<Ui::Radioenum<HistoryVisibility>>(
|
||||
container,
|
||||
box->setTitle(tr::lng_manage_history_visibility_title());
|
||||
box->addButton(tr::lng_settings_save(), [=] {
|
||||
savedCallback(historyVisibility->value());
|
||||
box->closeBox();
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
|
||||
box->addSkip(st::editPeerHistoryVisibilityTopSkip);
|
||||
box->addRow(object_ptr<Ui::Radioenum<HistoryVisibility>>(
|
||||
box,
|
||||
historyVisibility,
|
||||
value,
|
||||
groupText,
|
||||
st::defaultBoxCheckbox));
|
||||
container->add(object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
|
||||
container,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
std::move(groupAbout),
|
||||
st::editPeerPrivacyLabel),
|
||||
st::editPeerPreHistoryLabelMargins));
|
||||
}
|
||||
|
||||
void FillContent(
|
||||
not_null<Ui::VerticalLayout*> parent,
|
||||
not_null<PeerData*> peer,
|
||||
std::shared_ptr<Ui::RadioenumGroup<HistoryVisibility>> historyVisibility,
|
||||
HistoryVisibility savedValue) {
|
||||
const auto canEdit = [&] {
|
||||
if (const auto chat = peer->asChat()) {
|
||||
return chat->canEditPreHistoryHidden();
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
return channel->canEditPreHistoryHidden();
|
||||
}
|
||||
Unexpected("User in HistoryVisibilityEdit.");
|
||||
}();
|
||||
if (!canEdit) {
|
||||
return;
|
||||
}
|
||||
|
||||
historyVisibility->setValue(savedValue);
|
||||
|
||||
const auto result = parent->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
parent,
|
||||
object_ptr<Ui::VerticalLayout>(parent),
|
||||
st::editPeerHistoryVisibilityMargins));
|
||||
const auto container = result->entity();
|
||||
|
||||
Assert(historyVisibility != nullptr);
|
||||
|
||||
AddRadioButton(
|
||||
container,
|
||||
HistoryVisibility::Visible,
|
||||
tr::lng_manage_history_visibility_shown(tr::now),
|
||||
tr::lng_manage_history_visibility_shown_about(),
|
||||
historyVisibility);
|
||||
AddRadioButton(
|
||||
container,
|
||||
st::defaultBoxCheckbox));
|
||||
box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_manage_history_visibility_shown_about(),
|
||||
st::editPeerPrivacyLabel),
|
||||
st::editPeerPreHistoryLabelMargins + st::boxRowPadding);
|
||||
|
||||
box->addSkip(st::editPeerHistoryVisibilityTopSkip);
|
||||
box->addRow(object_ptr<Ui::Radioenum<HistoryVisibility>>(
|
||||
box,
|
||||
historyVisibility,
|
||||
HistoryVisibility::Hidden,
|
||||
tr::lng_manage_history_visibility_hidden(tr::now),
|
||||
(peer->isChat()
|
||||
? tr::lng_manage_history_visibility_hidden_legacy
|
||||
: tr::lng_manage_history_visibility_hidden_about)(),
|
||||
historyVisibility);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
EditPeerHistoryVisibilityBox::EditPeerHistoryVisibilityBox(
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
FnMut<void(HistoryVisibility)> savedCallback,
|
||||
HistoryVisibility historyVisibilitySavedValue)
|
||||
: _peer(peer)
|
||||
, _savedCallback(std::move(savedCallback))
|
||||
, _historyVisibilitySavedValue(historyVisibilitySavedValue)
|
||||
, _historyVisibility(
|
||||
std::make_shared<Ui::RadioenumGroup<HistoryVisibility>>(
|
||||
_historyVisibilitySavedValue)) {
|
||||
}
|
||||
|
||||
void EditPeerHistoryVisibilityBox::prepare() {
|
||||
_peer->updateFull();
|
||||
|
||||
setTitle(tr::lng_manage_history_visibility_title());
|
||||
addButton(tr::lng_settings_save(), [=] {
|
||||
auto local = std::move(_savedCallback);
|
||||
local(_historyVisibility->value());
|
||||
closeBox();
|
||||
});
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
setupContent();
|
||||
}
|
||||
|
||||
void EditPeerHistoryVisibilityBox::setupContent() {
|
||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
FillContent(
|
||||
content,
|
||||
_peer,
|
||||
_historyVisibility,
|
||||
_historyVisibilitySavedValue);
|
||||
setDimensionsToContent(st::boxWidth, content);
|
||||
st::defaultBoxCheckbox));
|
||||
box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
(isLegacy
|
||||
? tr::lng_manage_history_visibility_hidden_legacy
|
||||
: tr::lng_manage_history_visibility_hidden_about)(),
|
||||
st::editPeerPrivacyLabel),
|
||||
st::editPeerPreHistoryLabelMargins + st::boxRowPadding);
|
||||
}
|
||||
|
||||
@@ -7,32 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
namespace Ui {
|
||||
class GenericBox;
|
||||
} // namespace Ui
|
||||
|
||||
enum class HistoryVisibility {
|
||||
Visible,
|
||||
Hidden,
|
||||
};
|
||||
|
||||
class EditPeerHistoryVisibilityBox : public Ui::BoxContent {
|
||||
public:
|
||||
EditPeerHistoryVisibilityBox(
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
FnMut<void(HistoryVisibility)> savedCallback,
|
||||
HistoryVisibility historyVisibilitySavedValue);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
void setupContent();
|
||||
|
||||
not_null<PeerData*> _peer;
|
||||
FnMut<void(HistoryVisibility)> _savedCallback;
|
||||
|
||||
HistoryVisibility _historyVisibilitySavedValue;
|
||||
std::shared_ptr<Ui::RadioenumGroup<HistoryVisibility>> _historyVisibility;
|
||||
|
||||
};
|
||||
void EditPeerHistoryVisibilityBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
bool isLegacy,
|
||||
Fn<void(HistoryVisibility)> savedCallback,
|
||||
HistoryVisibility historyVisibilitySavedValue);
|
||||
|
||||
@@ -37,9 +37,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/admin_log/history_admin_log_section.h"
|
||||
#include "info/profile/info_profile_values.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "ui/toast/toast.h"
|
||||
@@ -53,22 +52,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "facades.h"
|
||||
#include "facades.h" // Ui::showChatsList
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
auto ToPositiveNumberString() {
|
||||
[[nodiscard]] auto ToPositiveNumberString() {
|
||||
return rpl::map([](int count) {
|
||||
return count ? QString::number(count) : QString();
|
||||
});
|
||||
}
|
||||
|
||||
auto ToPositiveNumberStringRestrictions() {
|
||||
[[nodiscard]] auto ToPositiveNumberStringRestrictions() {
|
||||
return rpl::map([](int count) {
|
||||
return QString::number(count)
|
||||
+ QString("/")
|
||||
@@ -94,40 +93,29 @@ void AddButtonWithCount(
|
||||
rpl::producer<QString> &&text,
|
||||
rpl::producer<QString> &&count,
|
||||
Fn<void()> callback,
|
||||
const style::icon &icon) {
|
||||
Settings::IconDescriptor &&descriptor) {
|
||||
parent->add(EditPeerInfoBox::CreateButton(
|
||||
parent,
|
||||
std::move(text),
|
||||
std::move(count),
|
||||
std::move(callback),
|
||||
st::manageGroupButton,
|
||||
&icon));
|
||||
std::move(descriptor)));
|
||||
}
|
||||
|
||||
object_ptr<Ui::SettingsButton> CreateButtonWithText(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Ui::SettingsButton*> AddButtonWithText(
|
||||
not_null<Ui::VerticalLayout*> parent,
|
||||
rpl::producer<QString> &&text,
|
||||
rpl::producer<QString> &&label,
|
||||
Fn<void()> callback) {
|
||||
return EditPeerInfoBox::CreateButton(
|
||||
Fn<void()> callback,
|
||||
Settings::IconDescriptor &&descriptor) {
|
||||
return parent->add(EditPeerInfoBox::CreateButton(
|
||||
parent,
|
||||
std::move(text),
|
||||
std::move(label),
|
||||
std::move(callback),
|
||||
st::manageGroupTopButtonWithText,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
Ui::SettingsButton *AddButtonWithText(
|
||||
not_null<Ui::VerticalLayout*> parent,
|
||||
rpl::producer<QString> &&text,
|
||||
rpl::producer<QString> &&label,
|
||||
Fn<void()> callback) {
|
||||
return parent->add(CreateButtonWithText(
|
||||
parent,
|
||||
std::move(text),
|
||||
std::move(label),
|
||||
std::move(callback)));
|
||||
std::move(descriptor)));
|
||||
}
|
||||
|
||||
void AddButtonDelete(
|
||||
@@ -140,7 +128,7 @@ void AddButtonDelete(
|
||||
rpl::single(QString()),
|
||||
std::move(callback),
|
||||
st::manageDeleteGroupButton,
|
||||
nullptr));
|
||||
{}));
|
||||
}
|
||||
|
||||
void SaveDefaultRestrictions(
|
||||
@@ -262,7 +250,7 @@ public:
|
||||
not_null<Ui::BoxContent*> box,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
object_ptr<Ui::VerticalLayout> createContent();
|
||||
[[nodiscard]] object_ptr<Ui::VerticalLayout> createContent();
|
||||
void setFocus();
|
||||
|
||||
private:
|
||||
@@ -284,12 +272,12 @@ private:
|
||||
std::optional<ChannelData*> linkedChat;
|
||||
};
|
||||
|
||||
object_ptr<Ui::RpWidget> createPhotoAndTitleEdit();
|
||||
object_ptr<Ui::RpWidget> createTitleEdit();
|
||||
object_ptr<Ui::RpWidget> createPhotoEdit();
|
||||
object_ptr<Ui::RpWidget> createDescriptionEdit();
|
||||
object_ptr<Ui::RpWidget> createManageGroupButtons();
|
||||
object_ptr<Ui::RpWidget> createStickersEdit();
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> createPhotoAndTitleEdit();
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> createTitleEdit();
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> createPhotoEdit();
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> createDescriptionEdit();
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> createManageGroupButtons();
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> createStickersEdit();
|
||||
|
||||
[[nodiscard]] bool canEditInformation() const;
|
||||
[[nodiscard]] bool canEditReactions() const;
|
||||
@@ -310,14 +298,14 @@ private:
|
||||
void deleteWithConfirmation();
|
||||
void deleteChannel();
|
||||
|
||||
std::optional<Saving> validate() const;
|
||||
bool validateUsername(Saving &to) const;
|
||||
bool validateLinkedChat(Saving &to) const;
|
||||
bool validateTitle(Saving &to) const;
|
||||
bool validateDescription(Saving &to) const;
|
||||
bool validateHistoryVisibility(Saving &to) const;
|
||||
bool validateSignatures(Saving &to) const;
|
||||
bool validateForwards(Saving &to) const;
|
||||
[[nodiscard]] std::optional<Saving> validate() const;
|
||||
[[nodiscard]] bool validateUsername(Saving &to) const;
|
||||
[[nodiscard]] bool validateLinkedChat(Saving &to) const;
|
||||
[[nodiscard]] bool validateTitle(Saving &to) const;
|
||||
[[nodiscard]] bool validateDescription(Saving &to) const;
|
||||
[[nodiscard]] bool validateHistoryVisibility(Saving &to) const;
|
||||
[[nodiscard]] bool validateSignatures(Saving &to) const;
|
||||
[[nodiscard]] bool validateForwards(Saving &to) const;
|
||||
|
||||
void save();
|
||||
void saveUsername();
|
||||
@@ -522,7 +510,8 @@ object_ptr<Ui::RpWidget> Controller::createDescriptionEdit() {
|
||||
result->entity()->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
result->entity()->setInstantReplacesEnabled(
|
||||
Core::App().settings().replaceEmojiValue());
|
||||
result->entity()->setSubmitSettings(Core::App().settings().sendSubmitWay());
|
||||
result->entity()->setSubmitSettings(
|
||||
Core::App().settings().sendSubmitWay());
|
||||
Ui::Emoji::SuggestionsController::Init(
|
||||
_wrap->window(),
|
||||
result->entity(),
|
||||
@@ -739,7 +728,8 @@ void Controller::fillPrivacyTypeButton() {
|
||||
? tr::lng_manage_private_group_title
|
||||
: tr::lng_manage_private_peer_title)();
|
||||
}) | rpl::flatten_latest(),
|
||||
[=] { showEditPeerTypeBox(); });
|
||||
[=] { showEditPeerTypeBox(); },
|
||||
{ &st::infoIconGroupType, Settings::kIconLightBlue });
|
||||
|
||||
_privacyTypeUpdates.fire_copy(*_privacySavedValue);
|
||||
}
|
||||
@@ -781,7 +771,8 @@ void Controller::fillLinkedChatButton() {
|
||||
_controls.buttonsLayout,
|
||||
std::move(text),
|
||||
std::move(label),
|
||||
[=] { showEditLinkedChatBox(); });
|
||||
[=] { showEditLinkedChatBox(); },
|
||||
{ &st::settingsIconChat, Settings::kIconGreen });
|
||||
_linkedChatUpdates.fire_copy(*_linkedChatSavedValue);
|
||||
}
|
||||
//
|
||||
@@ -803,13 +794,16 @@ void Controller::fillSignaturesButton() {
|
||||
Expects(_controls.buttonsLayout != nullptr);
|
||||
|
||||
const auto channel = _peer->asChannel();
|
||||
if (!channel) return;
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddButtonWithText(
|
||||
_controls.buttonsLayout,
|
||||
tr::lng_edit_sign_messages(),
|
||||
rpl::single(QString()),
|
||||
[=] {}
|
||||
[] {},
|
||||
{ &st::infoIconSignature, Settings::kIconLightBlue }
|
||||
)->toggleOn(rpl::single(channel->addsSignature())
|
||||
)->toggledValue(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
@@ -843,12 +837,23 @@ void Controller::fillHistoryVisibilityButton() {
|
||||
_historyVisibilitySavedValue = checked;
|
||||
});
|
||||
const auto buttonCallback = [=] {
|
||||
_navigation->parentController()->show(
|
||||
Box<EditPeerHistoryVisibilityBox>(
|
||||
_peer,
|
||||
boxCallback,
|
||||
*_historyVisibilitySavedValue),
|
||||
Ui::LayerOption::KeepOther);
|
||||
_peer->updateFull();
|
||||
const auto canEdit = [&] {
|
||||
if (const auto chat = _peer->asChat()) {
|
||||
return chat->canEditPreHistoryHidden();
|
||||
} else if (const auto channel = _peer->asChannel()) {
|
||||
return channel->canEditPreHistoryHidden();
|
||||
}
|
||||
Unexpected("User in HistoryVisibilityEdit.");
|
||||
}();
|
||||
if (!canEdit) {
|
||||
return;
|
||||
}
|
||||
_navigation->parentController()->show(Box(
|
||||
EditPeerHistoryVisibilityBox,
|
||||
_peer->isChat(),
|
||||
boxCallback,
|
||||
*_historyVisibilitySavedValue));
|
||||
};
|
||||
AddButtonWithText(
|
||||
container,
|
||||
@@ -859,7 +864,8 @@ void Controller::fillHistoryVisibilityButton() {
|
||||
? tr::lng_manage_history_visibility_shown
|
||||
: tr::lng_manage_history_visibility_hidden)();
|
||||
}) | rpl::flatten_latest(),
|
||||
buttonCallback);
|
||||
buttonCallback,
|
||||
{ &st::settingsIconChat, Settings::kIconGreen });
|
||||
|
||||
updateHistoryVisibility->fire_copy(*_historyVisibilitySavedValue);
|
||||
|
||||
@@ -970,6 +976,40 @@ void Controller::fillManageSection() {
|
||||
st::editPeerTopButtonsLayoutSkipCustomBottom);
|
||||
}
|
||||
|
||||
if (canEditReactions()) {
|
||||
const auto session = &_peer->session();
|
||||
auto reactionsCount = Info::Profile::MigratedOrMeValue(
|
||||
_peer
|
||||
) | rpl::map(
|
||||
Info::Profile::AllowedReactionsCountValue
|
||||
) | rpl::flatten_latest();
|
||||
auto fullCount = Info::Profile::FullReactionsCountValue(session);
|
||||
auto label = rpl::combine(
|
||||
std::move(reactionsCount),
|
||||
std::move(fullCount)
|
||||
) | rpl::map([=](int allowed, int total) {
|
||||
return allowed
|
||||
? QString::number(allowed) + " / " + QString::number(total)
|
||||
: tr::lng_manage_peer_reactions_off(tr::now);
|
||||
});
|
||||
const auto done = [=](const std::vector<QString> &chosen) {
|
||||
SaveAllowedReactions(_peer, chosen);
|
||||
};
|
||||
AddButtonWithCount(
|
||||
_controls.buttonsLayout,
|
||||
tr::lng_manage_peer_reactions(),
|
||||
std::move(label),
|
||||
[=] {
|
||||
_navigation->parentController()->show(Box(
|
||||
EditAllowedReactionsBox,
|
||||
!_peer->isBroadcast(),
|
||||
session->data().reactions().list(
|
||||
Data::Reactions::Type::Active),
|
||||
*Data::PeerAllowedReactions(_peer),
|
||||
done));
|
||||
},
|
||||
{ &st::infoIconReactions, Settings::kIconRed });
|
||||
}
|
||||
if (canEditPermissions) {
|
||||
AddButtonWithCount(
|
||||
_controls.buttonsLayout,
|
||||
@@ -981,7 +1021,7 @@ void Controller::fillManageSection() {
|
||||
) | rpl::flatten_latest(
|
||||
) | ToPositiveNumberStringRestrictions(),
|
||||
[=] { ShowEditPermissions(_navigation, _peer); },
|
||||
st::infoIconPermissions);
|
||||
{ &st::settingsIconKey, Settings::kIconGreen });
|
||||
}
|
||||
if (canEditInviteLinks) {
|
||||
auto count = Info::Profile::MigratedOrMeValue(
|
||||
@@ -1017,7 +1057,7 @@ void Controller::fillManageSection() {
|
||||
0),
|
||||
Ui::LayerOption::KeepOther);
|
||||
},
|
||||
st::infoIconInviteLinks);
|
||||
{ &st::infoIconInviteLinks, Settings::kIconLightOrange });
|
||||
|
||||
if (_privacySavedValue) {
|
||||
_privacyTypeUpdates.events_starting_with_copy(
|
||||
@@ -1029,40 +1069,6 @@ void Controller::fillManageSection() {
|
||||
}, wrap->lifetime());
|
||||
}
|
||||
}
|
||||
if (canEditReactions()) {
|
||||
const auto session = &_peer->session();
|
||||
auto reactionsCount = Info::Profile::MigratedOrMeValue(
|
||||
_peer
|
||||
) | rpl::map(
|
||||
Info::Profile::AllowedReactionsCountValue
|
||||
) | rpl::flatten_latest();
|
||||
auto fullCount = Info::Profile::FullReactionsCountValue(session);
|
||||
auto label = rpl::combine(
|
||||
std::move(reactionsCount),
|
||||
std::move(fullCount)
|
||||
) | rpl::map([=](int allowed, int total) {
|
||||
return allowed
|
||||
? QString::number(allowed) + " / " + QString::number(total)
|
||||
: tr::lng_manage_peer_reactions_off(tr::now);
|
||||
});
|
||||
const auto done = [=](const std::vector<QString> &chosen) {
|
||||
SaveAllowedReactions(_peer, chosen);
|
||||
};
|
||||
AddButtonWithCount(
|
||||
_controls.buttonsLayout,
|
||||
tr::lng_manage_peer_reactions(),
|
||||
std::move(label),
|
||||
[=] {
|
||||
_navigation->parentController()->show(Box(
|
||||
EditAllowedReactionsBox,
|
||||
!_peer->isBroadcast(),
|
||||
session->data().reactions().list(
|
||||
Data::Reactions::Type::Active),
|
||||
*Data::PeerAllowedReactions(_peer),
|
||||
done));
|
||||
},
|
||||
st::infoIconReactions);
|
||||
}
|
||||
if (canViewAdmins) {
|
||||
AddButtonWithCount(
|
||||
_controls.buttonsLayout,
|
||||
@@ -1079,12 +1085,14 @@ void Controller::fillManageSection() {
|
||||
_peer,
|
||||
ParticipantsBoxController::Role::Admins);
|
||||
},
|
||||
st::infoIconAdministrators);
|
||||
{ &st::infoIconAdministrators, Settings::kIconLightBlue });
|
||||
}
|
||||
if (canViewMembers) {
|
||||
AddButtonWithCount(
|
||||
_controls.buttonsLayout,
|
||||
(_isGroup ? tr::lng_manage_peer_members() : tr::lng_manage_peer_subscribers()),
|
||||
(_isGroup
|
||||
? tr::lng_manage_peer_members()
|
||||
: tr::lng_manage_peer_subscribers()),
|
||||
Info::Profile::MigratedOrMeValue(
|
||||
_peer
|
||||
) | rpl::map(
|
||||
@@ -1097,7 +1105,7 @@ void Controller::fillManageSection() {
|
||||
_peer,
|
||||
ParticipantsBoxController::Role::Members);
|
||||
},
|
||||
st::infoIconMembers);
|
||||
{ &st::settingsIconGroup, Settings::kIconDarkBlue });
|
||||
}
|
||||
|
||||
fillPendingRequestsButton();
|
||||
@@ -1114,7 +1122,7 @@ void Controller::fillManageSection() {
|
||||
_peer,
|
||||
ParticipantsBoxController::Role::Kicked);
|
||||
},
|
||||
st::infoIconBlacklist);
|
||||
{ &st::settingsIconMinus, Settings::kIconRed });
|
||||
}
|
||||
if (hasRecentActions) {
|
||||
auto callback = [=] {
|
||||
@@ -1126,7 +1134,7 @@ void Controller::fillManageSection() {
|
||||
tr::lng_manage_peer_recent_actions(),
|
||||
rpl::single(QString()), //Empty count.
|
||||
std::move(callback),
|
||||
st::infoIconRecentActions);
|
||||
{ &st::infoIconRecentActions, Settings::kIconPurple });
|
||||
}
|
||||
|
||||
if (canEditStickers || canDeleteChannel) {
|
||||
@@ -1168,7 +1176,7 @@ void Controller::fillPendingRequestsButton() {
|
||||
: tr::lng_manage_peer_requests_channel()),
|
||||
rpl::duplicate(pendingRequestsCount) | ToPositiveNumberString(),
|
||||
[=] { RequestsBoxController::Start(_navigation, _peer); },
|
||||
st::infoIconRequests);
|
||||
{ &st::infoIconRequests, Settings::kIconRed });
|
||||
std::move(
|
||||
pendingRequestsCount
|
||||
) | rpl::start_with_next([=](int count) {
|
||||
@@ -1670,18 +1678,18 @@ object_ptr<Ui::SettingsButton> EditPeerInfoBox::CreateButton(
|
||||
rpl::producer<QString> &&count,
|
||||
Fn<void()> callback,
|
||||
const style::SettingsCountButton &st,
|
||||
const style::icon *icon) {
|
||||
Settings::IconDescriptor &&descriptor) {
|
||||
auto result = object_ptr<Ui::SettingsButton>(
|
||||
parent,
|
||||
rpl::duplicate(text),
|
||||
st.button);
|
||||
const auto button = result.data();
|
||||
button->addClickHandler(callback);
|
||||
if (icon) {
|
||||
Ui::CreateChild<Info::Profile::FloatingIcon>(
|
||||
if (descriptor) {
|
||||
AddButtonIcon(
|
||||
button,
|
||||
*icon,
|
||||
st.iconPosition);
|
||||
st.button,
|
||||
std::move(descriptor));
|
||||
}
|
||||
|
||||
auto labelText = rpl::combine(
|
||||
|
||||
@@ -7,8 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <rpl/event_stream.h>
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
namespace Settings {
|
||||
struct IconDescriptor;
|
||||
} // namespace Settings
|
||||
|
||||
namespace style {
|
||||
struct SettingsCountButton;
|
||||
@@ -42,7 +45,7 @@ public:
|
||||
rpl::producer<QString> &&count,
|
||||
Fn<void()> callback,
|
||||
const style::SettingsCountButton &st,
|
||||
const style::icon *icon = nullptr);
|
||||
Settings::IconDescriptor &&descriptor);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
@@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
@@ -612,7 +613,8 @@ void EditPeerPermissionsBox::addSuggestGigagroup(
|
||||
AboutGigagroupCallback(
|
||||
_peer->asChannel(),
|
||||
_navigation->parentController()),
|
||||
st::peerPermissionsButton));
|
||||
st::peerPermissionsButton,
|
||||
{}));
|
||||
|
||||
container->add(
|
||||
object_ptr<Ui::DividerLabel>(
|
||||
@@ -645,7 +647,8 @@ void EditPeerPermissionsBox::addBannedButtons(
|
||||
_peer,
|
||||
ParticipantsBoxController::Role::Restricted);
|
||||
},
|
||||
st::peerPermissionsButton));
|
||||
st::peerPermissionsButton,
|
||||
{}));
|
||||
if (channel) {
|
||||
container->add(EditPeerInfoBox::CreateButton(
|
||||
container,
|
||||
@@ -658,7 +661,8 @@ void EditPeerPermissionsBox::addBannedButtons(
|
||||
_peer,
|
||||
ParticipantsBoxController::Role::Kicked);
|
||||
},
|
||||
st::peerPermissionsButton));
|
||||
st::peerPermissionsButton,
|
||||
{}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,92 +7,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/peers/edit_peer_reactions.h"
|
||||
|
||||
#include "boxes/reactions_settings_box.h" // AddReactionLottieIcon
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "lottie/lottie_icon.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_info.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using Data::Reaction;
|
||||
|
||||
void AddReactionIcon(
|
||||
not_null<Ui::RpWidget*> button,
|
||||
not_null<DocumentData*> document) {
|
||||
struct State {
|
||||
std::shared_ptr<Data::DocumentMedia> media;
|
||||
std::unique_ptr<Lottie::Icon> icon;
|
||||
QImage image;
|
||||
};
|
||||
|
||||
const auto size = st::editPeerReactionsPreview;
|
||||
const auto state = button->lifetime().make_state<State>(State{
|
||||
.media = document->createMediaView(),
|
||||
});
|
||||
const auto icon = Ui::CreateChild<Ui::RpWidget>(button.get());
|
||||
icon->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
icon->resize(size, size);
|
||||
button->sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
icon->moveToLeft(
|
||||
st::editPeerReactionsIconLeft,
|
||||
(size.height() - icon->height()) / 2,
|
||||
size.width());
|
||||
}, icon->lifetime());
|
||||
|
||||
const auto initLottie = [=] {
|
||||
state->icon = Lottie::MakeIcon({
|
||||
.path = state->media->owner()->filepath(true),
|
||||
.json = state->media->bytes(),
|
||||
.sizeOverride = QSize(size, size),
|
||||
.frame = -1,
|
||||
});
|
||||
state->media = nullptr;
|
||||
};
|
||||
state->media->checkStickerLarge();
|
||||
if (state->media->loaded()) {
|
||||
initLottie();
|
||||
} else {
|
||||
document->session().downloaderTaskFinished(
|
||||
) | rpl::filter([=] {
|
||||
return state->media->loaded();
|
||||
}) | rpl::take(1) | rpl::start_with_next([=] {
|
||||
initLottie();
|
||||
icon->update();
|
||||
}, icon->lifetime());
|
||||
}
|
||||
|
||||
icon->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
QPainter p(icon);
|
||||
if (state->image.isNull() && state->icon) {
|
||||
state->image = state->icon->frame();
|
||||
crl::async([icon = std::move(state->icon)]{});
|
||||
}
|
||||
if (!state->image.isNull()) {
|
||||
p.drawImage(QRect(0, 0, size, size), state->image);
|
||||
}
|
||||
}, icon->lifetime());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void EditAllowedReactionsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
bool isGroup,
|
||||
const std::vector<Reaction> &list,
|
||||
const std::vector<Data::Reaction> &list,
|
||||
const base::flat_set<QString> &selected,
|
||||
Fn<void(const std::vector<QString> &)> callback) {
|
||||
box->setTitle(tr::lng_manage_peer_reactions());
|
||||
@@ -153,9 +87,23 @@ void EditAllowedReactionsBox(
|
||||
container,
|
||||
rpl::single(entry.title),
|
||||
st::manageGroupButton.button);
|
||||
AddReactionIcon(button, entry.centerIcon
|
||||
? entry.centerIcon
|
||||
: entry.appearAnimation.get());
|
||||
const auto iconHeight = st::editPeerReactionsPreview;
|
||||
AddReactionLottieIcon(
|
||||
button,
|
||||
button->sizeValue(
|
||||
) | rpl::map([=](const QSize &size) {
|
||||
return QPoint(
|
||||
st::editPeerReactionsIconLeft,
|
||||
(size.height() - iconHeight) / 2);
|
||||
}),
|
||||
iconHeight,
|
||||
entry,
|
||||
button->events(
|
||||
) | rpl::filter([=](not_null<QEvent*> event) {
|
||||
return event->type() == QEvent::Enter;
|
||||
}) | rpl::to_empty,
|
||||
rpl::never<>(),
|
||||
&button->lifetime());
|
||||
state->toggles.emplace(entry.emoji, button);
|
||||
button->toggleOn(rpl::single(
|
||||
active(entry)
|
||||
|
||||
@@ -7,14 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/layers/generic_box.h"
|
||||
|
||||
class PeerData;
|
||||
|
||||
namespace Data {
|
||||
struct Reaction;
|
||||
} // namespace Data
|
||||
|
||||
namespace Ui {
|
||||
class GenericBox;
|
||||
} // namespace Ui
|
||||
|
||||
void EditAllowedReactionsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
bool isGroup,
|
||||
|
||||
@@ -7,8 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/peers/edit_peer_type_box.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "main/main_session.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
@@ -19,7 +17,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/peers/edit_peer_invite_link.h"
|
||||
#include "boxes/peers/edit_peer_invite_links.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "core/application.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_peer.h"
|
||||
@@ -27,7 +24,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_changes.h"
|
||||
#include "info/profile/info_profile_values.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwindow.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/special_buttons.h"
|
||||
@@ -35,7 +31,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
@@ -48,11 +43,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
#include <rpl/flatten_latest.h>
|
||||
|
||||
namespace {
|
||||
|
||||
class Controller : public base::has_weak_ptr {
|
||||
@@ -209,21 +199,22 @@ void Controller::createContent() {
|
||||
Ui::LayerOption::KeepOther);
|
||||
},
|
||||
st::manageGroupButton,
|
||||
&st::infoIconInviteLinks));
|
||||
{ &st::infoIconInviteLinks, Settings::kIconLightOrange }));
|
||||
AddSkip(_wrap.get());
|
||||
AddDividerText(_wrap.get(), tr::lng_group_invite_manage_about());
|
||||
|
||||
if (!_linkOnly) {
|
||||
AddSkip(_wrap.get());
|
||||
AddSubsectionTitle(_wrap.get(), tr::lng_manage_peer_no_forwards_title());
|
||||
AddSubsectionTitle(
|
||||
_wrap.get(),
|
||||
tr::lng_manage_peer_no_forwards_title());
|
||||
_controls.noForwards = _wrap->add(EditPeerInfoBox::CreateButton(
|
||||
_wrap.get(),
|
||||
tr::lng_manage_peer_no_forwards(),
|
||||
rpl::single(QString()),
|
||||
[=] {},
|
||||
st::manageGroupTopButtonWithText,
|
||||
nullptr
|
||||
));
|
||||
[] {},
|
||||
st::peerPermissionsButton,
|
||||
{}));
|
||||
_controls.noForwards->toggleOn(
|
||||
rpl::single(_noForwardsSavedValue.value_or(false))
|
||||
)->toggledValue(
|
||||
|
||||
@@ -7,8 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "base/timer.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
namespace style {
|
||||
struct SettingsCountButton;
|
||||
|
||||
@@ -234,7 +234,6 @@ void AddMessage(
|
||||
(rightSize.height() - iconSize) / 2);
|
||||
}),
|
||||
iconSize,
|
||||
&controller->session(),
|
||||
r,
|
||||
rpl::never<>(),
|
||||
rpl::duplicate(emojiValue) | rpl::skip(1) | rpl::to_empty,
|
||||
@@ -251,7 +250,6 @@ void AddReactionLottieIcon(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
rpl::producer<QPoint> iconPositionValue,
|
||||
int iconSize,
|
||||
not_null<Main::Session*> session,
|
||||
const Data::Reaction &reaction,
|
||||
rpl::producer<> &&selects,
|
||||
rpl::producer<> &&destroys,
|
||||
@@ -280,7 +278,7 @@ void AddReactionLottieIcon(
|
||||
state->appear.media->checkStickerLarge();
|
||||
state->select.media->checkStickerLarge();
|
||||
rpl::single() | rpl::then(
|
||||
session->downloaderTaskFinished()
|
||||
reaction.appearAnimation->session().downloaderTaskFinished()
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto check = [&](State::Entry &entry) {
|
||||
if (!entry.media) {
|
||||
@@ -448,7 +446,6 @@ void ReactionsSettingsBox(
|
||||
(s.height() - iconSize) / 2);
|
||||
}),
|
||||
iconSize,
|
||||
&controller->session(),
|
||||
r,
|
||||
button->events(
|
||||
) | rpl::filter([=](not_null<QEvent*> event) {
|
||||
|
||||
@@ -16,10 +16,6 @@ namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Data {
|
||||
struct Reaction;
|
||||
} // namespace Data
|
||||
@@ -28,7 +24,6 @@ void AddReactionLottieIcon(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
rpl::producer<QPoint> iconPositionValue,
|
||||
int iconSize,
|
||||
not_null<Main::Session*> session,
|
||||
const Data::Reaction &reaction,
|
||||
rpl::producer<> &&selects,
|
||||
rpl::producer<> &&destroys,
|
||||
|
||||
106
Telegram/SourceFiles/boxes/report_messages_box.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
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 "boxes/report_messages_box.h"
|
||||
|
||||
#include "api/api_report.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/boxes/report_box.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> Report(
|
||||
not_null<PeerData*> peer,
|
||||
std::variant<v::null_t, MessageIdsList, not_null<PhotoData*>> data) {
|
||||
const auto source = v::match(data, [](const MessageIdsList &ids) {
|
||||
return Ui::ReportSource::Message;
|
||||
}, [](not_null<PhotoData*> photo) {
|
||||
return photo->hasVideo()
|
||||
? Ui::ReportSource::ProfileVideo
|
||||
: Ui::ReportSource::ProfilePhoto;
|
||||
}, [](v::null_t) {
|
||||
Unexpected("Bad source report.");
|
||||
return Ui::ReportSource::Bot;
|
||||
});
|
||||
return Box([=](not_null<Ui::GenericBox*> box) {
|
||||
Ui::ReportReasonBox(box, source, [=](Ui::ReportReason reason) {
|
||||
Ui::BoxShow(box).showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
const auto show = Ui::BoxShow(box);
|
||||
Ui::ReportDetailsBox(box, [=](const QString &text) {
|
||||
const auto toastParent = show.toastParent();
|
||||
Api::SendReport(toastParent, peer, reason, text, data);
|
||||
show.hideLayer();
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
object_ptr<Ui::BoxContent> ReportItemsBox(
|
||||
not_null<PeerData*> peer,
|
||||
MessageIdsList ids) {
|
||||
return Report(peer, ids);
|
||||
}
|
||||
|
||||
object_ptr<Ui::BoxContent> ReportProfilePhotoBox(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<PhotoData*> photo) {
|
||||
return Report(peer, photo);
|
||||
}
|
||||
|
||||
void ShowReportPeerBox(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<PeerData*> peer) {
|
||||
struct State {
|
||||
QPointer<Ui::BoxContent> reasonBox;
|
||||
QPointer<Ui::BoxContent> detailsBox;
|
||||
MessageIdsList ids;
|
||||
};
|
||||
const auto state = std::make_shared<State>();
|
||||
const auto chosen = [=](Ui::ReportReason reason) {
|
||||
const auto send = [=](const QString &text) {
|
||||
window->clearChooseReportMessages();
|
||||
Api::SendReport(
|
||||
Window::Show(window).toastParent(),
|
||||
peer,
|
||||
reason,
|
||||
text,
|
||||
std::move(state->ids));
|
||||
if (const auto strong = state->reasonBox.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
if (const auto strong = state->detailsBox.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
if (reason == Ui::ReportReason::Fake
|
||||
|| reason == Ui::ReportReason::Other) {
|
||||
state->ids = {};
|
||||
state->detailsBox = window->show(Box(Ui::ReportDetailsBox, send));
|
||||
return;
|
||||
}
|
||||
window->showChooseReportMessages(peer, reason, [=](
|
||||
MessageIdsList ids) {
|
||||
state->ids = std::move(ids);
|
||||
state->detailsBox = window->show(Box(Ui::ReportDetailsBox, send));
|
||||
});
|
||||
};
|
||||
state->reasonBox = window->show(Box(
|
||||
Ui::ReportReasonBox,
|
||||
(peer->isBroadcast()
|
||||
? Ui::ReportSource::Channel
|
||||
: peer->isUser()
|
||||
? Ui::ReportSource::Bot
|
||||
: Ui::ReportSource::Group),
|
||||
chosen));
|
||||
}
|
||||
31
Telegram/SourceFiles/boxes/report_messages_box.h
Normal file
@@ -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
|
||||
|
||||
template <typename Object>
|
||||
class object_ptr;
|
||||
|
||||
namespace Ui {
|
||||
class BoxContent;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Main
|
||||
|
||||
class PeerData;
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> ReportItemsBox(
|
||||
not_null<PeerData*> peer,
|
||||
MessageIdsList ids);
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> ReportProfilePhotoBox(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<PhotoData*> photo);
|
||||
void ShowReportPeerBox(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<PeerData*> peer);
|
||||
@@ -1065,6 +1065,7 @@ void GroupCall::start(TimeId scheduleDate, bool rtmp) {
|
||||
MTPstring(), // title
|
||||
MTP_int(scheduleDate)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_reloadedStaleCall = true;
|
||||
_acceptFields = true;
|
||||
_peer->session().api().applyUpdates(result);
|
||||
_acceptFields = false;
|
||||
@@ -1393,6 +1394,13 @@ void GroupCall::rejoin(not_null<PeerData*> as) {
|
||||
sendSelfUpdate(SendUpdateType::CameraPaused);
|
||||
}
|
||||
sendPendingSelfUpdates();
|
||||
if (!_reloadedStaleCall
|
||||
&& _state.current() != State::Joining) {
|
||||
if (const auto real = lookupReal()) {
|
||||
_reloadedStaleCall = true;
|
||||
real->reloadIfStale();
|
||||
}
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_joinState.finish();
|
||||
|
||||
|
||||
@@ -674,6 +674,7 @@ private:
|
||||
bool _hadJoinedState = false;
|
||||
bool _listenersHidden = false;
|
||||
bool _rtmp = false;
|
||||
bool _reloadedStaleCall = false;
|
||||
int _rtmpVolume = 0;
|
||||
|
||||
std::unique_ptr<Webrtc::MediaDevices> _mediaDevices;
|
||||
|
||||
@@ -239,8 +239,9 @@ QByteArray Settings::serialize() const {
|
||||
}
|
||||
|
||||
stream
|
||||
<< qint32(_hardwareAcceleratedVideo ? 1 : 0)
|
||||
<< qint32(_chatQuickAction);
|
||||
<< qint32(0) // old hardwareAcceleratedVideo
|
||||
<< qint32(_chatQuickAction)
|
||||
<< qint32(_hardwareAcceleratedVideo ? 1 : 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -514,11 +515,15 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
}
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
stream >> hardwareAcceleratedVideo;
|
||||
qint32 legacyHardwareAcceleratedVideo = 0;
|
||||
stream >> legacyHardwareAcceleratedVideo;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
stream >> chatQuickAction;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
stream >> hardwareAcceleratedVideo;
|
||||
}
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: "
|
||||
"Bad data for Core::Settings::constructFromSerialized()"));
|
||||
|
||||
@@ -792,7 +792,11 @@ private:
|
||||
rpl::variable<Media::Player::OrderMode> _playerOrderMode;
|
||||
bool _macWarnBeforeQuit = true;
|
||||
std::vector<uint64> _accountsOrder;
|
||||
#ifdef Q_OS_MAC
|
||||
bool _hardwareAcceleratedVideo = true;
|
||||
#else // Q_OS_MAC
|
||||
bool _hardwareAcceleratedVideo = false;
|
||||
#endif // Q_OS_MAC
|
||||
HistoryView::DoubleClickQuickAction _chatQuickAction =
|
||||
HistoryView::DoubleClickQuickAction();
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QTimer>
|
||||
#include <qpa/qplatformscreen.h>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -43,7 +44,18 @@ PreLaunchWindow::PreLaunchWindow(QString title) {
|
||||
p.setColor(QPalette::Window, QColor(255, 255, 255));
|
||||
setPalette(p);
|
||||
|
||||
_size = QFontMetrics(QGuiApplication::font()).height();
|
||||
constexpr auto processDpi = [](const QDpi &dpi) {
|
||||
return (dpi.first + dpi.second) * 0.5;
|
||||
};
|
||||
|
||||
const auto screen = QGuiApplication::primaryScreen();
|
||||
const auto scale = processDpi(screen->handle()->logicalDpi())
|
||||
/ processDpi(screen->handle()->logicalBaseDpi());
|
||||
|
||||
auto font = QGuiApplication::font();
|
||||
font.setPixelSize(base::SafeRound(font.pointSize() * scale));
|
||||
|
||||
_size = QFontMetrics(font).height();
|
||||
|
||||
int paddingVertical = (_size / 2);
|
||||
int paddingHorizontal = _size;
|
||||
|
||||
@@ -219,8 +219,8 @@ void Sandbox::launchApplication() {
|
||||
}
|
||||
|
||||
void Sandbox::setupScreenScale() {
|
||||
const auto processDpi = [](const QDpi &dpi) {
|
||||
return (dpi.first + dpi.second) * qreal(0.5);
|
||||
constexpr auto processDpi = [](const QDpi &dpi) {
|
||||
return (dpi.first + dpi.second) * 0.5;
|
||||
};
|
||||
const auto dpi = processDpi(
|
||||
Sandbox::primaryScreen()->handle()->logicalDpi());
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 3007000;
|
||||
constexpr auto AppVersionStr = "3.7";
|
||||
constexpr auto AppVersion = 3007002;
|
||||
constexpr auto AppVersionStr = "3.7.2";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -208,4 +208,8 @@ UpdatedFileReferences GetFileReferences(
|
||||
return GetFileReferencesHelper(data);
|
||||
}
|
||||
|
||||
UpdatedFileReferences GetFileReferences(const MTPMessageMedia &data) {
|
||||
return GetFileReferencesHelper(data);
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
@@ -179,4 +179,7 @@ UpdatedFileReferences GetFileReferences(const MTPTheme &data);
|
||||
UpdatedFileReferences GetFileReferences(
|
||||
const MTPaccount_SavedRingtones &data);
|
||||
|
||||
// Admin Log Event.
|
||||
UpdatedFileReferences GetFileReferences(const MTPMessageMedia &data);
|
||||
|
||||
} // namespace Data
|
||||
|
||||
@@ -26,6 +26,7 @@ constexpr auto kRequestPerPage = 50;
|
||||
constexpr auto kSpeakingAfterActive = crl::time(6000);
|
||||
constexpr auto kActiveAfterJoined = crl::time(1000);
|
||||
constexpr auto kWaitForUpdatesTimeout = 3 * crl::time(1000);
|
||||
constexpr auto kReloadStaleTimeout = 16 * crl::time(1000);
|
||||
|
||||
[[nodiscard]] QString ExtractNextOffset(const MTPphone_GroupCall &call) {
|
||||
return call.match([&](const MTPDphone_groupCall &data) {
|
||||
@@ -168,6 +169,7 @@ bool GroupCall::processSavedFullCall() {
|
||||
return false;
|
||||
}
|
||||
_reloadRequestId = 0;
|
||||
_reloadLastFinished = crl::now();
|
||||
processFullCallFields(*base::take(_savedFull));
|
||||
return true;
|
||||
}
|
||||
@@ -497,6 +499,15 @@ void GroupCall::computeParticipantsCount() {
|
||||
: std::max(int(_participants.size()), _serverParticipantsCount);
|
||||
}
|
||||
|
||||
void GroupCall::reloadIfStale() {
|
||||
if (!fullCount() && !participantsLoaded()) {
|
||||
reload();
|
||||
} else if (!_reloadLastFinished
|
||||
|| crl::now() > _reloadLastFinished + kReloadStaleTimeout) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
void GroupCall::reload() {
|
||||
if (_reloadRequestId || _applyingQueuedUpdates) {
|
||||
return;
|
||||
@@ -528,9 +539,11 @@ void GroupCall::reload() {
|
||||
return;
|
||||
}
|
||||
_reloadRequestId = 0;
|
||||
_reloadLastFinished = crl::now();
|
||||
processFullCall(result);
|
||||
}).fail([=] {
|
||||
_reloadRequestId = 0;
|
||||
_reloadLastFinished = crl::now();
|
||||
}).send();
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ public:
|
||||
|
||||
void setInCall();
|
||||
void reload();
|
||||
void reloadIfStale();
|
||||
void processFullCall(const MTPphone_GroupCall &call);
|
||||
|
||||
void setJoinMutedLocally(bool muted);
|
||||
@@ -206,6 +207,7 @@ private:
|
||||
int _version = 0;
|
||||
mtpRequestId _participantsRequestId = 0;
|
||||
mtpRequestId _reloadRequestId = 0;
|
||||
crl::time _reloadLastFinished = 0;
|
||||
rpl::variable<QString> _title;
|
||||
|
||||
base::flat_multi_map<
|
||||
|
||||
@@ -86,6 +86,8 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
|
||||
}
|
||||
|
||||
[[nodiscard]] bool InitHw(AVCodecContext *context, AVHWDeviceType type) {
|
||||
AVCodecContext *parent = static_cast<AVCodecContext*>(context->opaque);
|
||||
|
||||
auto hwDeviceContext = (AVBufferRef*)nullptr;
|
||||
AvErrorWrap error = av_hwdevice_ctx_create(
|
||||
&hwDeviceContext,
|
||||
@@ -101,11 +103,13 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
|
||||
"Trying \"%1\" hardware acceleration for \"%2\" decoder."
|
||||
).arg(av_hwdevice_get_type_name(type)
|
||||
).arg(context->codec->name));
|
||||
if (context->hw_device_ctx) {
|
||||
av_buffer_unref(&context->hw_device_ctx);
|
||||
if (parent->hw_device_ctx) {
|
||||
av_buffer_unref(&parent->hw_device_ctx);
|
||||
}
|
||||
context->hw_device_ctx = av_buffer_ref(hwDeviceContext);
|
||||
parent->hw_device_ctx = av_buffer_ref(hwDeviceContext);
|
||||
av_buffer_unref(&hwDeviceContext);
|
||||
|
||||
context->hw_device_ctx = parent->hw_device_ctx;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -294,6 +298,7 @@ CodecPointer MakeCodecPointer(CodecDescriptor descriptor) {
|
||||
|
||||
if (descriptor.hwAllowed) {
|
||||
context->get_format = GetHwFormat;
|
||||
context->opaque = context;
|
||||
} else {
|
||||
DEBUG_LOG(("Video Info: Using software \"%2\" decoder."
|
||||
).arg(codec->name));
|
||||
|
||||
@@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_chat_participants.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_session.h"
|
||||
#include "lang/lang_keys.h"
|
||||
@@ -136,6 +137,18 @@ bool MediaCanHaveCaption(const MTPMessage &message) {
|
||||
|| (mediaType == mtpc_messageMediaPhoto);
|
||||
}
|
||||
|
||||
uint64 MediaId(const MTPMessage &message) {
|
||||
if (!MediaCanHaveCaption(message)) {
|
||||
return 0;
|
||||
}
|
||||
const auto &media = message.c_message().vmedia();
|
||||
return media
|
||||
? v::match(
|
||||
Data::GetFileReferences(*media).data.begin()->first,
|
||||
[](const auto &d) { return d.id; })
|
||||
: 0;
|
||||
}
|
||||
|
||||
TextWithEntities ExtractEditedText(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPMessage &message) {
|
||||
@@ -868,22 +881,36 @@ void GenerateItems(
|
||||
const auto newValue = ExtractEditedText(
|
||||
session,
|
||||
action.vnew_message());
|
||||
auto oldValue = ExtractEditedText(
|
||||
session,
|
||||
action.vprev_message());
|
||||
|
||||
const auto canHaveCaption = MediaCanHaveCaption(
|
||||
action.vnew_message());
|
||||
const auto changedCaption = (newValue != oldValue);
|
||||
const auto changedMedia = MediaId(action.vnew_message())
|
||||
!= MediaId(action.vprev_message());
|
||||
const auto removedCaption = !oldValue.text.isEmpty()
|
||||
&& newValue.text.isEmpty();
|
||||
const auto text = (!canHaveCaption
|
||||
? tr::lng_admin_log_edited_message
|
||||
: newValue.text.isEmpty()
|
||||
: (changedMedia && removedCaption)
|
||||
? tr::lng_admin_log_edited_media_and_removed_caption
|
||||
: (changedMedia && changedCaption)
|
||||
? tr::lng_admin_log_edited_media_and_caption
|
||||
: changedMedia
|
||||
? tr::lng_admin_log_edited_media
|
||||
: removedCaption
|
||||
? tr::lng_admin_log_removed_caption
|
||||
: tr::lng_admin_log_edited_caption)(
|
||||
: changedCaption
|
||||
? tr::lng_admin_log_edited_caption
|
||||
: tr::lng_admin_log_edited_message)(
|
||||
tr::now,
|
||||
lt_from,
|
||||
fromLinkText,
|
||||
Ui::Text::WithEntities);
|
||||
addSimpleServiceMessage(text);
|
||||
|
||||
auto oldValue = ExtractEditedText(
|
||||
session,
|
||||
action.vprev_message());
|
||||
const auto detachExistingItem = false;
|
||||
const auto body = history->createItem(
|
||||
history->nextNonHistoryEntryId(),
|
||||
|
||||
@@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/notifications_manager.h"
|
||||
#include "boxes/about_sponsored_box.h"
|
||||
#include "boxes/delete_messages_box.h"
|
||||
#include "boxes/report_messages_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "chat_helpers/emoji_interactions.h"
|
||||
@@ -2247,7 +2248,8 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
_menu,
|
||||
poll,
|
||||
item,
|
||||
HistoryView::Context::History);
|
||||
HistoryView::Context::History,
|
||||
_controller);
|
||||
} else if (const auto contact = media->sharedContact()) {
|
||||
const auto phone = contact->phoneNumber;
|
||||
_menu->addAction(tr::lng_profile_copy_phone(tr::now), [=] {
|
||||
@@ -3864,17 +3866,17 @@ void HistoryInner::deleteAsGroup(FullMsgId itemId) {
|
||||
}
|
||||
|
||||
void HistoryInner::reportItem(FullMsgId itemId) {
|
||||
HistoryView::ShowReportItemsBox(_peer, { 1, itemId });
|
||||
_controller->show(ReportItemsBox(_peer, { 1, itemId }));
|
||||
}
|
||||
|
||||
void HistoryInner::reportAsGroup(FullMsgId itemId) {
|
||||
if (const auto item = session().data().message(itemId)) {
|
||||
const auto group = session().data().groups().find(item);
|
||||
HistoryView::ShowReportItemsBox(
|
||||
_controller->show(ReportItemsBox(
|
||||
_peer,
|
||||
(group
|
||||
? session().data().itemsToIds(group->items)
|
||||
: MessageIdsList{ 1, itemId }));
|
||||
: MessageIdsList{ 1, itemId })));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_editing.h"
|
||||
#include "api/api_bot.h"
|
||||
#include "api/api_chat_participants.h"
|
||||
#include "api/api_report.h"
|
||||
#include "api/api_sending.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "api/api_send_progress.h"
|
||||
@@ -3877,19 +3878,18 @@ void HistoryWidget::reportSelectedMessages() {
|
||||
const auto ids = _list->getSelectedItems();
|
||||
const auto peer = _peer;
|
||||
const auto reason = _chooseForReport->reason;
|
||||
const auto box = std::make_shared<QPointer<Ui::GenericBox>>();
|
||||
const auto weak = Ui::MakeWeak(_list.data());
|
||||
const auto send = [=](const QString &text) {
|
||||
if (weak) {
|
||||
clearSelected();
|
||||
controller()->clearChooseReportMessages();
|
||||
}
|
||||
HistoryView::SendReport(peer, reason, text, ids);
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
};
|
||||
*box = controller()->window().show(Box(Ui::ReportDetailsBox, send));
|
||||
controller()->window().show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
Ui::ReportDetailsBox(box, [=](const QString &text) {
|
||||
if (weak) {
|
||||
clearSelected();
|
||||
controller()->clearChooseReportMessages();
|
||||
}
|
||||
const auto toastParent = Window::Show(controller()).toastParent();
|
||||
Api::SendReport(toastParent, peer, reason, text, ids);
|
||||
box->closeBox();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
History *HistoryWidget::history() const {
|
||||
@@ -6388,25 +6388,28 @@ void HistoryWidget::checkPinnedBarState() {
|
||||
auto barContent = HistoryView::PinnedBarContent(
|
||||
&session(),
|
||||
_pinnedTracker->shownMessageId());
|
||||
_pinnedBar = std::make_unique<Ui::PinnedBar>(
|
||||
this,
|
||||
std::move(barContent));
|
||||
Info::Profile::SharedMediaCountValue(
|
||||
_peer,
|
||||
nullptr,
|
||||
Storage::SharedMediaType::Pinned
|
||||
) | rpl::distinct_until_changed(
|
||||
) | rpl::map([=](int count) {
|
||||
if (_pinnedClickedId) {
|
||||
_pinnedClickedId = FullMsgId();
|
||||
_minPinnedId = std::nullopt;
|
||||
updatePinnedViewer();
|
||||
}
|
||||
return (count > 1);
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool many) {
|
||||
refreshPinnedBarButton(many);
|
||||
_pinnedBar = std::make_unique<Ui::PinnedBar>(this);
|
||||
rpl::combine(
|
||||
Info::Profile::SharedMediaCountValue(
|
||||
_peer,
|
||||
nullptr,
|
||||
Storage::SharedMediaType::Pinned
|
||||
) | rpl::distinct_until_changed(
|
||||
) | rpl::map([=](int count) {
|
||||
if (_pinnedClickedId) {
|
||||
_pinnedClickedId = FullMsgId();
|
||||
_minPinnedId = std::nullopt;
|
||||
updatePinnedViewer();
|
||||
}
|
||||
return (count > 1);
|
||||
}) | rpl::distinct_until_changed(),
|
||||
HistoryView::PinnedBarItemWithReplyMarkup(
|
||||
&session(),
|
||||
_pinnedTracker->shownMessageId())
|
||||
) | rpl::start_with_next([=](bool many, HistoryItem *item) {
|
||||
refreshPinnedBarButton(many, item);
|
||||
}, _pinnedBar->lifetime());
|
||||
_pinnedBar->setContent(std::move(barContent));
|
||||
|
||||
controller()->adaptive().oneColumnValue(
|
||||
) | rpl::start_with_next([=](bool one) {
|
||||
@@ -6493,7 +6496,30 @@ void HistoryWidget::setChooseReportMessagesDetails(
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::refreshPinnedBarButton(bool many) {
|
||||
void HistoryWidget::refreshPinnedBarButton(bool many, HistoryItem *item) {
|
||||
if (const auto replyMarkup = item ? item->inlineReplyMarkup() : nullptr) {
|
||||
const auto &rows = replyMarkup->data.rows;
|
||||
if ((rows.size() == 1) && (rows.front().size() == 1)) {
|
||||
const auto text = rows.front().front().text;
|
||||
if (!text.isEmpty()) {
|
||||
auto button = object_ptr<Ui::RoundButton>(
|
||||
this,
|
||||
rpl::single(text),
|
||||
st::historyPinnedBotButton);
|
||||
button->setTextTransform(
|
||||
Ui::RoundButton::TextTransform::NoTransform);
|
||||
button->setFullRadius(true);
|
||||
button->setClickedCallback([=] {
|
||||
App::activateBotCommand(controller(), item, 0, 0);
|
||||
});
|
||||
if (button->width() > st::historyPinnedBotButtonMaxWidth) {
|
||||
button->setFullWidth(st::historyPinnedBotButtonMaxWidth);
|
||||
}
|
||||
_pinnedBar->setRightButton(std::move(button));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto close = !many;
|
||||
auto button = object_ptr<Ui::IconButton>(
|
||||
this,
|
||||
|
||||
@@ -512,7 +512,7 @@ private:
|
||||
void updatePinnedViewer();
|
||||
void setupPinnedTracker();
|
||||
void checkPinnedBarState();
|
||||
void refreshPinnedBarButton(bool many);
|
||||
void refreshPinnedBarButton(bool many, HistoryItem *item);
|
||||
void checkLastPinnedClickedIdReset(
|
||||
int wasScrollTop,
|
||||
int nowScrollTop);
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_attached_stickers.h"
|
||||
#include "api/api_editing.h"
|
||||
#include "api/api_polls.h"
|
||||
#include "api/api_report.h"
|
||||
#include "api/api_ringtones.h"
|
||||
#include "api/api_who_reacted.h"
|
||||
#include "api/api_toggling_media.h" // Api::ToggleFavedSticker
|
||||
@@ -34,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "menu/menu_send.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/delete_messages_box.h"
|
||||
#include "boxes/report_messages_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
@@ -54,11 +56,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/window_session_controller.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "core/application.h"
|
||||
#include "mainwidget.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "apiwrap.h"
|
||||
#include "facades.h"
|
||||
#include "facades.h" // LambdaDelayed
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
@@ -806,11 +807,11 @@ void AddReportAction(
|
||||
const auto callback = crl::guard(controller, [=] {
|
||||
if (const auto item = owner->message(itemId)) {
|
||||
const auto group = owner->groups().find(item);
|
||||
ShowReportItemsBox(
|
||||
controller->show(ReportItemsBox(
|
||||
item->history()->peer,
|
||||
(group
|
||||
? owner->itemsToIds(group->items)
|
||||
: MessageIdsList{ 1, itemId }));
|
||||
: MessageIdsList{ 1, itemId })));
|
||||
}
|
||||
});
|
||||
menu->addAction(
|
||||
@@ -960,7 +961,8 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
|
||||
} else if (lnkDocument) {
|
||||
AddDocumentActions(result, lnkDocument, item, list);
|
||||
} else if (poll) {
|
||||
AddPollActions(result, poll, item, list->elementContext());
|
||||
const auto context = list->elementContext();
|
||||
AddPollActions(result, poll, item, context, list->controller());
|
||||
} else if (!request.overSelection && view && !hasSelection) {
|
||||
const auto owner = &view->data()->history()->owner();
|
||||
const auto media = view->media();
|
||||
@@ -1034,26 +1036,12 @@ void CopyPostLink(
|
||||
: tr::lng_context_about_private_link(tr::now));
|
||||
}
|
||||
|
||||
void StopPoll(not_null<Main::Session*> session, FullMsgId itemId) {
|
||||
const auto stop = [=] {
|
||||
Ui::hideLayer();
|
||||
if (const auto item = session->data().message(itemId)) {
|
||||
session->api().polls().close(item);
|
||||
}
|
||||
};
|
||||
Ui::show(Ui::MakeConfirmBox({
|
||||
.text = tr::lng_polls_stop_warning(),
|
||||
.confirmed = stop,
|
||||
.confirmText = tr::lng_polls_stop_sure(),
|
||||
.cancelText = tr::lng_cancel(),
|
||||
}));
|
||||
}
|
||||
|
||||
void AddPollActions(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<PollData*> poll,
|
||||
not_null<HistoryItem*> item,
|
||||
Context context) {
|
||||
Context context,
|
||||
not_null<Window::SessionController*> controller) {
|
||||
if ((context != Context::History)
|
||||
&& (context != Context::Replies)
|
||||
&& (context != Context::Pinned)) {
|
||||
@@ -1070,7 +1058,17 @@ void AddPollActions(
|
||||
}
|
||||
if (item->canStopPoll()) {
|
||||
menu->addAction(tr::lng_polls_stop(tr::now), [=] {
|
||||
StopPoll(&poll->session(), itemId);
|
||||
controller->show(Ui::MakeConfirmBox({
|
||||
.text = tr::lng_polls_stop_warning(),
|
||||
.confirmed = [=](Fn<void()> &&close) {
|
||||
close();
|
||||
if (const auto item = poll->owner().message(itemId)) {
|
||||
controller->session().api().polls().close(item);
|
||||
}
|
||||
},
|
||||
.confirmText = tr::lng_polls_stop_sure(),
|
||||
.cancelText = tr::lng_cancel(),
|
||||
}));
|
||||
}, &st::menuIconStopPoll);
|
||||
}
|
||||
}
|
||||
@@ -1204,108 +1202,4 @@ void ShowWhoReactedMenu(
|
||||
}, lifetime);
|
||||
}
|
||||
|
||||
void ShowReportItemsBox(not_null<PeerData*> peer, MessageIdsList ids) {
|
||||
const auto chosen = [=](Ui::ReportReason reason) {
|
||||
Ui::show(Box(Ui::ReportDetailsBox, [=](const QString &text) {
|
||||
SendReport(peer, reason, text, ids);
|
||||
Ui::hideLayer();
|
||||
}));
|
||||
};
|
||||
Ui::show(Box(
|
||||
Ui::ReportReasonBox,
|
||||
Ui::ReportSource::Message,
|
||||
chosen));
|
||||
}
|
||||
|
||||
void ShowReportPeerBox(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<PeerData*> peer) {
|
||||
struct State {
|
||||
QPointer<Ui::GenericBox> reasonBox;
|
||||
QPointer<Ui::GenericBox> detailsBox;
|
||||
MessageIdsList ids;
|
||||
};
|
||||
const auto state = std::make_shared<State>();
|
||||
const auto chosen = [=](Ui::ReportReason reason) {
|
||||
const auto send = [=](const QString &text) {
|
||||
window->clearChooseReportMessages();
|
||||
SendReport(peer, reason, text, std::move(state->ids));
|
||||
if (const auto strong = state->reasonBox.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
if (const auto strong = state->detailsBox.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
if (reason == Ui::ReportReason::Fake
|
||||
|| reason == Ui::ReportReason::Other) {
|
||||
state->ids = {};
|
||||
state->detailsBox = window->window().show(
|
||||
Box(Ui::ReportDetailsBox, send));
|
||||
return;
|
||||
}
|
||||
window->showChooseReportMessages(peer, reason, [=](
|
||||
MessageIdsList ids) {
|
||||
state->ids = std::move(ids);
|
||||
state->detailsBox = window->window().show(
|
||||
Box(Ui::ReportDetailsBox, send));
|
||||
});
|
||||
};
|
||||
state->reasonBox = window->window().show(Box(
|
||||
Ui::ReportReasonBox,
|
||||
(peer->isBroadcast()
|
||||
? Ui::ReportSource::Channel
|
||||
: peer->isUser()
|
||||
? Ui::ReportSource::Bot
|
||||
: Ui::ReportSource::Group),
|
||||
chosen));
|
||||
}
|
||||
|
||||
void SendReport(
|
||||
not_null<PeerData*> peer,
|
||||
Ui::ReportReason reason,
|
||||
const QString &comment,
|
||||
MessageIdsList ids) {
|
||||
const auto apiReason = [&] {
|
||||
using Reason = Ui::ReportReason;
|
||||
switch (reason) {
|
||||
case Reason::Spam: return MTP_inputReportReasonSpam();
|
||||
case Reason::Fake: return MTP_inputReportReasonFake();
|
||||
case Reason::Violence: return MTP_inputReportReasonViolence();
|
||||
case Reason::ChildAbuse: return MTP_inputReportReasonChildAbuse();
|
||||
case Reason::Pornography: return MTP_inputReportReasonPornography();
|
||||
case Reason::Copyright: return MTP_inputReportReasonCopyright();
|
||||
case Reason::IllegalDrugs:
|
||||
return MTP_inputReportReasonIllegalDrugs();
|
||||
case Reason::PersonalDetails:
|
||||
return MTP_inputReportReasonPersonalDetails();
|
||||
case Reason::Other: return MTP_inputReportReasonOther();
|
||||
}
|
||||
Unexpected("Bad reason group value.");
|
||||
}();
|
||||
if (ids.empty()) {
|
||||
peer->session().api().request(MTPaccount_ReportPeer(
|
||||
peer->input,
|
||||
apiReason,
|
||||
MTP_string(comment)
|
||||
)).done([=] {
|
||||
Ui::Toast::Show(tr::lng_report_thanks(tr::now));
|
||||
}).send();
|
||||
} else {
|
||||
auto apiIds = QVector<MTPint>();
|
||||
apiIds.reserve(ids.size());
|
||||
for (const auto &fullId : ids) {
|
||||
apiIds.push_back(MTP_int(fullId.msg));
|
||||
}
|
||||
peer->session().api().request(MTPmessages_Report(
|
||||
peer->input,
|
||||
MTP_vector<MTPint>(apiIds),
|
||||
apiReason,
|
||||
MTP_string(comment)
|
||||
)).done([=] {
|
||||
Ui::Toast::Show(tr::lng_report_thanks(tr::now));
|
||||
}).send();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
||||
@@ -54,12 +54,12 @@ void CopyPostLink(
|
||||
not_null<Main::Session*> session,
|
||||
FullMsgId itemId,
|
||||
Context context);
|
||||
void StopPoll(not_null<Main::Session*> session, FullMsgId itemId);
|
||||
void AddPollActions(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<PollData*> poll,
|
||||
not_null<HistoryItem*> item,
|
||||
Context context);
|
||||
Context context,
|
||||
not_null<Window::SessionController*> controller);
|
||||
void AddSaveSoundForNotifications(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<HistoryItem*> item,
|
||||
@@ -79,14 +79,4 @@ void ShowWhoReactedMenu(
|
||||
not_null<Window::SessionController*> controller,
|
||||
rpl::lifetime &lifetime);
|
||||
|
||||
void ShowReportItemsBox(not_null<PeerData*> peer, MessageIdsList ids);
|
||||
void ShowReportPeerBox(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<PeerData*> peer);
|
||||
void SendReport(
|
||||
not_null<PeerData*> peer,
|
||||
Ui::ReportReason reason,
|
||||
const QString &comment,
|
||||
MessageIdsList ids = {});
|
||||
|
||||
} // namespace HistoryView
|
||||
|
||||
@@ -364,9 +364,8 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallBarContentByPeer(
|
||||
-> rpl::producer<Ui::GroupCallBarContent> {
|
||||
if (!call) {
|
||||
return rpl::single(Ui::GroupCallBarContent{ .shown = false });
|
||||
} else if (!call->fullCount() && !call->participantsLoaded()) {
|
||||
call->reload();
|
||||
}
|
||||
call->reloadIfStale();
|
||||
return GroupCallBarContentByCall(call, userpicSize);
|
||||
}) | rpl::flatten_latest();
|
||||
}
|
||||
|
||||
@@ -154,4 +154,56 @@ rpl::producer<Ui::MessageBarContent> PinnedBarContent(
|
||||
}) | rpl::flatten_latest();
|
||||
}
|
||||
|
||||
rpl::producer<HistoryItem*> PinnedBarItemWithReplyMarkup(
|
||||
not_null<Main::Session*> session,
|
||||
rpl::producer<PinnedId> id) {
|
||||
return rpl::make_producer<HistoryItem*>([=,
|
||||
id = std::move(id)](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
consumer.put_next(nullptr);
|
||||
|
||||
struct State {
|
||||
HistoryMessageReplyMarkup *previousReplyMarkup = nullptr;
|
||||
rpl::lifetime lifetime;
|
||||
};
|
||||
const auto state = lifetime.make_state<State>();
|
||||
|
||||
const auto pushUnique = [=](not_null<HistoryItem*> item) {
|
||||
const auto replyMarkup = item->inlineReplyMarkup();
|
||||
if (state->previousReplyMarkup == replyMarkup) {
|
||||
return;
|
||||
}
|
||||
consumer.put_next(item.get());
|
||||
state->previousReplyMarkup = replyMarkup;
|
||||
};
|
||||
|
||||
rpl::duplicate(
|
||||
id
|
||||
) | rpl::start_with_next([=](PinnedId current) {
|
||||
const auto fullId = current.message;
|
||||
if (!fullId) {
|
||||
return;
|
||||
}
|
||||
const auto messageFlag = [=](not_null<HistoryItem*> item) {
|
||||
using Update = Data::MessageUpdate;
|
||||
session->changes().messageFlagsValue(
|
||||
item,
|
||||
Update::Flag::ReplyMarkup
|
||||
) | rpl::start_with_next([=](const Update &update) {
|
||||
pushUnique(update.item);
|
||||
}, state->lifetime);
|
||||
};
|
||||
if (const auto item = session->data().message(fullId)) {
|
||||
messageFlag(item);
|
||||
} else {
|
||||
session->api().requestMessageData(
|
||||
session->data().peer(fullId.peer),
|
||||
fullId.msg,
|
||||
[=] { messageFlag(session->data().message(fullId)); });
|
||||
}
|
||||
}, lifetime);
|
||||
return lifetime;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
||||
@@ -49,4 +49,8 @@ struct PinnedId {
|
||||
not_null<Main::Session*> session,
|
||||
rpl::producer<PinnedId> id);
|
||||
|
||||
[[nodiscard]] rpl::producer<HistoryItem*> PinnedBarItemWithReplyMarkup(
|
||||
not_null<Main::Session*> session,
|
||||
rpl::producer<PinnedId> id);
|
||||
|
||||
} // namespace HistoryView
|
||||
|
||||
@@ -388,7 +388,8 @@ void RepliesWidget::setupRootView() {
|
||||
) | rpl::map([=](Ui::MessageBarContent &&content, bool shown) {
|
||||
return shown ? std::move(content) : Ui::MessageBarContent();
|
||||
});
|
||||
_rootView = std::make_unique<Ui::PinnedBar>(this, std::move(content));
|
||||
_rootView = std::make_unique<Ui::PinnedBar>(this);
|
||||
_rootView->setContent(std::move(content));
|
||||
|
||||
controller()->adaptive().oneColumnValue(
|
||||
) | rpl::start_with_next([=](bool one) {
|
||||
|
||||
@@ -316,8 +316,7 @@ infoProfileSeparatorPadding: margins(
|
||||
|
||||
infoIconFg: windowBoldFg;
|
||||
infoIconInformation: icon {{ "info/info_information", infoIconFg }};
|
||||
//infoIconMembers: icon {{ "info/edit/group_manage_members", infoIconFg, point(-2px, 0px) }};
|
||||
infoIconRequests: icon {{ "info/info_add_member", infoIconFg, point(0px, 2px) }};
|
||||
infoIconRequests: icon {{ "info/info_add_member", infoIconFg }};
|
||||
infoIconNotifications: icon {{ "info/info_notifications", infoIconFg }};
|
||||
infoIconMediaPhoto: icon {{ "info/info_media_photo", infoIconFg }};
|
||||
infoIconMediaVideo: icon {{ "info/info_media_video", infoIconFg }};
|
||||
@@ -328,12 +327,12 @@ infoIconMediaLink: icon {{ "info/info_media_link", infoIconFg }};
|
||||
infoIconMediaGroup: icon {{ "info/info_common_groups", infoIconFg }};
|
||||
infoIconMediaVoice: icon {{ "info/info_media_voice", infoIconFg }};
|
||||
infoIconMediaRound: icon {{ "info/info_media_round", infoIconFg }};
|
||||
infoIconRecentActions: icon {{ "info/edit/group_manage_actions", infoIconFg, point(-2px, -1px) }};
|
||||
infoIconAdministrators: icon {{ "info/edit/group_manage_admins", infoIconFg, point(-3px, 0px) }};
|
||||
infoIconBlacklist: icon {{ "info/info_blacklist", infoIconFg, point(-2px, -2px) }};
|
||||
infoIconPermissions: icon {{ "info/edit/group_manage_permissions", infoIconFg, point(0px, -2px) }};
|
||||
infoIconInviteLinks: icon {{ "info/edit/group_manage_links", infoIconFg, point(-2px, 0px) }};
|
||||
infoIconReactions: icon {{ "info/edit/group_manage_reactions", infoIconFg }};
|
||||
infoIconRecentActions: icon {{ "info/edit/group_manage_actions", settingsIconFg }};
|
||||
infoIconAdministrators: icon {{ "info/edit/group_manage_admins", settingsIconFg }};
|
||||
infoIconInviteLinks: icon {{ "info/edit/group_manage_links", settingsIconFg }};
|
||||
infoIconReactions: icon {{ "info/edit/group_manage_reactions", settingsIconFg }};
|
||||
infoIconGroupType: icon {{ "info/edit/group_manage_type", settingsIconFg }};
|
||||
infoIconSignature: icon {{ "info/edit/channel_manage_signature", settingsIconFg }};
|
||||
infoIconShare: icon {{ "info/info_share", infoIconFg }};
|
||||
infoIconEdit: icon {{ "info/info_edit", infoIconFg }};
|
||||
infoIconDelete: icon {{ "info/info_delete", infoIconFg }};
|
||||
@@ -545,23 +544,20 @@ managePeerButton: SettingsCountButton {
|
||||
|
||||
peerPermissionsButton: SettingsCountButton(managePeerButton) {
|
||||
button: SettingsButton(infoProfileButton) {
|
||||
padding: margins(24px, 12px, 24px, 10px);
|
||||
padding: margins(22px, 12px, 24px, 10px);
|
||||
}
|
||||
iconPosition: point(24px, 5px);
|
||||
}
|
||||
|
||||
manageGroupButton: SettingsCountButton(managePeerButton) {
|
||||
button: SettingsButton(infoProfileButton) {
|
||||
padding: margins(72px, 10px, 24px, 8px);
|
||||
padding: margins(60px, 10px, 24px, 8px);
|
||||
}
|
||||
labelPosition: point(22px, 12px);
|
||||
iconPosition: point(20px, 4px);
|
||||
}
|
||||
|
||||
manageGroupTopButtonWithText: SettingsCountButton(manageGroupButton) {
|
||||
button: SettingsButton(infoProfileButton) {
|
||||
padding: margins(22px, 10px, 24px, 8px);
|
||||
}
|
||||
labelPosition: point(22px, 10px);
|
||||
iconPosition: point(0px, 0px);
|
||||
}
|
||||
@@ -608,7 +604,9 @@ editPeerHistoryVisibilityTopSkip: 8px;
|
||||
editPeerPhotoMargins: margins(22px, 16px, 22px, 8px);
|
||||
editPeerTitle: defaultInputField;
|
||||
editPeerTitleMargins: margins(27px, 21px, 22px, 8px);
|
||||
editPeerDescription: newGroupDescription;
|
||||
editPeerDescription: InputField(newGroupDescription) {
|
||||
borderFg: transparent;
|
||||
}
|
||||
editPeerDescriptionMargins: margins(22px, 5px, 22px, 16px);
|
||||
editPeerPrivaciesMargins: margins(15px, 7px, 22px, 0px);
|
||||
editPeerPrivacyTopSkip: 10px;
|
||||
@@ -657,8 +655,8 @@ editPeerInviteLinkBoxBottomSkip: 15px;
|
||||
editPeerReactionsButton: SettingsButton(infoProfileButton) {
|
||||
padding: margins(59px, 13px, 8px, 11px);
|
||||
}
|
||||
editPeerReactionsPreview: 48px;
|
||||
editPeerReactionsIconLeft: 12px;
|
||||
editPeerReactionsPreview: 24px;
|
||||
editPeerReactionsIconLeft: 21px;
|
||||
|
||||
historyTopBarBack: IconButton(infoTopBarBack) {
|
||||
width: 52px;
|
||||
|
||||
@@ -75,12 +75,13 @@ void ContentWidget::updateControlsGeometry() {
|
||||
if (!_innerWrap) {
|
||||
return;
|
||||
}
|
||||
_innerWrap->resizeToWidth(width());
|
||||
|
||||
auto newScrollTop = _scroll->scrollTop() + _topDelta;
|
||||
auto scrollGeometry = rect().marginsRemoved(
|
||||
QMargins(0, _scrollTopSkip.current(), 0, 0));
|
||||
if (_scroll->geometry() != scrollGeometry) {
|
||||
_scroll->setGeometry(scrollGeometry);
|
||||
_innerWrap->resizeToWidth(_scroll->width());
|
||||
}
|
||||
|
||||
if (!_scroll->isHidden()) {
|
||||
|
||||
@@ -105,10 +105,6 @@ void LayerWidget::setupHeightConsumers() {
|
||||
// New content arrived.
|
||||
_heightAnimated = _heightAnimation.animating();
|
||||
return;
|
||||
} else if (height < _desiredHeight
|
||||
&& height < st::columnMinimalWidthMain) {
|
||||
// Don't animate layer height to a very small one.
|
||||
return;
|
||||
}
|
||||
std::swap(_desiredHeight, height);
|
||||
if (!height
|
||||
|
||||
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
@@ -33,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "boxes/peers/add_bot_to_chat_box.h"
|
||||
#include "boxes/peers/edit_contact_box.h"
|
||||
#include "boxes/report_messages_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "menu/menu_mute.h"
|
||||
#include "info/info_controller.h"
|
||||
@@ -376,9 +378,21 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupMuteToggle() {
|
||||
tr::lng_profile_enable_notifications(),
|
||||
st::infoNotificationsButton);
|
||||
result->toggleOn(NotificationsEnabledValue(peer), true);
|
||||
result->setAcceptBoth();
|
||||
MuteMenu::SetupMuteMenu(
|
||||
result.data(),
|
||||
result->clicks() | rpl::to_empty,
|
||||
result->clicks(
|
||||
) | rpl::filter([=](Qt::MouseButton button) {
|
||||
if (button == Qt::RightButton) {
|
||||
return true;
|
||||
}
|
||||
if (peer->owner().notifySettings().isMuted(peer)) {
|
||||
peer->owner().notifySettings().update(peer, 0);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}) | rpl::to_empty,
|
||||
{ peer, std::make_shared<Window::Show>(_controller) });
|
||||
object_ptr<FloatingIcon>(
|
||||
result,
|
||||
@@ -619,7 +633,7 @@ void ActionsFiller::addReportAction() {
|
||||
const auto peer = _peer;
|
||||
const auto controller = _controller->parentController();
|
||||
const auto report = [=] {
|
||||
HistoryView::ShowReportPeerBox(controller, peer);
|
||||
ShowReportPeerBox(controller, peer);
|
||||
};
|
||||
AddActionButton(
|
||||
_wrap,
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "countries/countries_instance.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
@@ -81,9 +82,11 @@ rpl::producer<TextWithEntities> NameValue(not_null<PeerData*> peer) {
|
||||
}
|
||||
|
||||
rpl::producer<TextWithEntities> PhoneValue(not_null<UserData*> user) {
|
||||
return user->session().changes().peerFlagsValue(
|
||||
user,
|
||||
UpdateFlag::PhoneNumber
|
||||
return rpl::merge(
|
||||
Countries::Instance().updated(),
|
||||
user->session().changes().peerFlagsValue(
|
||||
user,
|
||||
UpdateFlag::PhoneNumber) | rpl::to_empty
|
||||
) | rpl::map([=] {
|
||||
return Ui::FormatPhone(user->phone());
|
||||
}) | Ui::Text::ToWithEntities();
|
||||
|
||||
@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/gl/gl_surface.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/delete_messages_box.h"
|
||||
#include "boxes/report_messages_box.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "media/view/media_view_playback_controls.h"
|
||||
#include "media/view/media_view_group_thumbs.h"
|
||||
@@ -509,10 +510,7 @@ void OverlayWidget::updateGeometry(bool inMove) {
|
||||
if (Platform::IsWayland()) {
|
||||
return;
|
||||
}
|
||||
const auto screen = _widget->screen()
|
||||
? _widget->screen()
|
||||
: QApplication::primaryScreen();
|
||||
const auto available = screen->geometry();
|
||||
const auto available = _widget->screen()->geometry();
|
||||
const auto openglWidget = _opengl
|
||||
? static_cast<QOpenGLWidget*>(_widget.get())
|
||||
: nullptr;
|
||||
@@ -1037,6 +1035,25 @@ void OverlayWidget::fillContextMenuActions(const MenuCallback &addAction) {
|
||||
peer->session().api().peerPhoto().set(peer, photo);
|
||||
}, &st::mediaMenuIconProfile);
|
||||
}();
|
||||
[&] { // Report userpic.
|
||||
if (!_peer
|
||||
|| !_photo
|
||||
|| _peer->isSelf()
|
||||
|| _peer->isNotificationsUser()
|
||||
|| !userPhotosKey()) {
|
||||
return;
|
||||
}
|
||||
const auto photo = _photo;
|
||||
const auto peer = _peer;
|
||||
addAction(tr::lng_mediaview_report_profile_photo(tr::now), [=] {
|
||||
if (const auto window = findWindow()) {
|
||||
close();
|
||||
window->show(
|
||||
ReportProfilePhotoBox(peer, photo),
|
||||
Ui::LayerOption::CloseOther);
|
||||
}
|
||||
}, &st::mediaMenuIconReport);
|
||||
}();
|
||||
}
|
||||
|
||||
auto OverlayWidget::computeOverviewType() const
|
||||
@@ -4746,6 +4763,7 @@ void OverlayWidget::clearBeforeHide() {
|
||||
_userPhotosData = std::nullopt;
|
||||
_collage = nullptr;
|
||||
_collageData = std::nullopt;
|
||||
clearStreaming();
|
||||
assignMediaPointer(nullptr);
|
||||
_preloadPhotos.clear();
|
||||
_preloadDocuments.clear();
|
||||
|
||||
@@ -477,14 +477,11 @@ void PipPanel::setPositionDefault() {
|
||||
if (parentScreen && myScreen && myScreen != parentScreen) {
|
||||
widget()->setScreen(parentScreen);
|
||||
}
|
||||
const auto screen = parentScreen
|
||||
? parentScreen
|
||||
: QGuiApplication::primaryScreen();
|
||||
auto position = Position();
|
||||
position.snapped = RectPart::Top | RectPart::Left;
|
||||
position.screen = screen->geometry();
|
||||
position.screen = parentScreen->geometry();
|
||||
position.geometry = QRect(0, 0, st::pipDefaultSize, st::pipDefaultSize);
|
||||
setPositionOnScreen(position, screen->availableGeometry());
|
||||
setPositionOnScreen(position, parentScreen->availableGeometry());
|
||||
}
|
||||
|
||||
void PipPanel::setPositionOnScreen(Position position, QRect available) {
|
||||
|
||||
@@ -128,6 +128,9 @@ void MuteItem::paintEvent(QPaintEvent *e) {
|
||||
st::settingsIconBg2,
|
||||
progress);
|
||||
p.setPen(color);
|
||||
|
||||
Action::paintBackground(p, Action::isSelected());
|
||||
RippleButton::paintRipple(p, 0, 0);
|
||||
Action::paintText(p);
|
||||
|
||||
const auto &icon = _isMuted ? st::menuIconUnmute : st::menuIconMute;
|
||||
@@ -177,14 +180,14 @@ void PickMuteBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
|
||||
(3600 * 4),
|
||||
(3600 * 8),
|
||||
(3600 * 12),
|
||||
(84600 * 1),
|
||||
(84600 * 2),
|
||||
(84600 * 3),
|
||||
(84600 * 7 * 1),
|
||||
(84600 * 7 * 2),
|
||||
(84600 * 30 * 1),
|
||||
(84600 * 30 * 2),
|
||||
(84600 * 30 * 3),
|
||||
(86400 * 1),
|
||||
(86400 * 2),
|
||||
(86400 * 3),
|
||||
(86400 * 7 * 1),
|
||||
(86400 * 7 * 2),
|
||||
(86400 * 31 * 1),
|
||||
(86400 * 31 * 2),
|
||||
(86400 * 31 * 3),
|
||||
};
|
||||
const auto phrases = ranges::views::all(
|
||||
seconds
|
||||
@@ -279,9 +282,13 @@ void FillMuteMenu(
|
||||
menu->addAction(std::move(item));
|
||||
}
|
||||
|
||||
const auto callback = [=, show = args.show] {
|
||||
DEBUG_LOG(("Mute Info: PickMuteBox called."));
|
||||
show->showBox(Box(PickMuteBox, peer));
|
||||
};
|
||||
menu->addAction(
|
||||
tr::lng_mute_menu_duration(tr::now),
|
||||
[=, show = args.show] { show->showBox(Box(PickMuteBox, peer)); },
|
||||
callback,
|
||||
&st::menuIconMuteFor);
|
||||
|
||||
menu->addAction(
|
||||
|
||||
@@ -173,13 +173,13 @@ void TTLBox(not_null<Ui::GenericBox*> box, Args args) {
|
||||
(86400 * 7 * 1),
|
||||
(86400 * 7 * 2),
|
||||
(86400 * 7 * 3),
|
||||
(86400 * 30 * 1),
|
||||
(86400 * 30 * 2),
|
||||
(86400 * 30 * 3),
|
||||
(86400 * 30 * 4),
|
||||
(86400 * 30 * 5),
|
||||
(86400 * 30 * 6),
|
||||
(86400 * 30 * 12),
|
||||
(86400 * 31 * 1),
|
||||
(86400 * 31 * 2),
|
||||
(86400 * 31 * 3),
|
||||
(86400 * 31 * 4),
|
||||
(86400 * 31 * 5),
|
||||
(86400 * 31 * 6),
|
||||
(86400 * 365),
|
||||
};
|
||||
const auto phrases = ranges::views::all(
|
||||
ttls
|
||||
|
||||
@@ -776,6 +776,9 @@ void Panel::showWebviewError(
|
||||
case Error::Wayland:
|
||||
rich.append(tr::lng_payments_webview_switch_wayland(tr::now));
|
||||
break;
|
||||
case Error::OldWindows:
|
||||
rich.append(tr::lng_payments_webview_update_windows(tr::now));
|
||||
break;
|
||||
default:
|
||||
rich.append(QString::fromStdString(information.details));
|
||||
break;
|
||||
|
||||
@@ -679,8 +679,12 @@ void NotificationData::setImage(const QString &imagePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto image = QImage(imagePath)
|
||||
.convertToFormat(QImage::Format_RGBA8888);
|
||||
const auto image = [&] {
|
||||
const auto original = QImage(imagePath);
|
||||
return original.hasAlphaChannel()
|
||||
? original.convertToFormat(QImage::Format_RGBA8888)
|
||||
: original.convertToFormat(QImage::Format_RGB888);
|
||||
}();
|
||||
|
||||
if (image.isNull()) {
|
||||
return;
|
||||
@@ -690,9 +694,9 @@ void NotificationData::setImage(const QString &imagePath) {
|
||||
image.width(),
|
||||
image.height(),
|
||||
int(image.bytesPerLine()),
|
||||
true,
|
||||
image.hasAlphaChannel(),
|
||||
8,
|
||||
4,
|
||||
image.hasAlphaChannel() ? 4 : 3,
|
||||
std::vector<uchar>(
|
||||
image.constBits(),
|
||||
image.constBits() + image.sizeInBytes()),
|
||||
|
||||
@@ -382,12 +382,6 @@ QString GetIconName() {
|
||||
std::optional<bool> IsDarkMode() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
[[maybe_unused]] static const auto Inited = [] {
|
||||
static const auto Setter = [] {
|
||||
crl::on_main([] {
|
||||
Core::App().settings().setSystemDarkMode(IsDarkMode());
|
||||
});
|
||||
};
|
||||
|
||||
using XDPSettingWatcher = base::Platform::XDP::SettingWatcher;
|
||||
static const XDPSettingWatcher Watcher(
|
||||
[=](
|
||||
@@ -396,7 +390,14 @@ std::optional<bool> IsDarkMode() {
|
||||
const Glib::VariantBase &value) {
|
||||
if (group == "org.freedesktop.appearance"
|
||||
&& key == "color-scheme") {
|
||||
Setter();
|
||||
try {
|
||||
const auto ivalue = base::Platform::GlibVariantCast<uint>(value);
|
||||
|
||||
crl::on_main([=] {
|
||||
Core::App().settings().setSystemDarkMode(ivalue == 1);
|
||||
});
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -410,10 +411,7 @@ std::optional<bool> IsDarkMode() {
|
||||
|
||||
if (result.has_value()) {
|
||||
const auto value = base::Platform::GlibVariantCast<uint>(*result);
|
||||
if (value == 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return value == 1;
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
@@ -630,7 +630,7 @@ void MainWindow::showFromTrayMenu() {
|
||||
// It will receive input events, but it will be rendered as inactive.
|
||||
using namespace rpl::mappers;
|
||||
_showFromTrayLifetime = trayIconMenu->shownValue(
|
||||
) | rpl::filter(_1) | rpl::take(1) | rpl::start_with_next([=] {
|
||||
) | rpl::filter(!_1) | rpl::take(1) | rpl::start_with_next([=] {
|
||||
showFromTray();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -903,7 +903,6 @@ void SetupMessages(
|
||||
r.top() + (r.height() - iconSize) / 2);
|
||||
}),
|
||||
iconSize,
|
||||
&controller->session(),
|
||||
r,
|
||||
buttonRight->events(
|
||||
) | rpl::filter([=](not_null<QEvent*> event) {
|
||||
|
||||
@@ -40,9 +40,15 @@ void ReportReasonBox(
|
||||
case Source::Channel: return tr::lng_report_title();
|
||||
case Source::Group: return tr::lng_report_group_title();
|
||||
case Source::Bot: return tr::lng_report_bot_title();
|
||||
case Source::ProfilePhoto:
|
||||
return tr::lng_report_profile_photo_title();
|
||||
case Source::ProfileVideo:
|
||||
return tr::lng_report_profile_video_title();
|
||||
}
|
||||
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,
|
||||
@@ -69,7 +75,7 @@ void ReportReasonBox(
|
||||
});
|
||||
};
|
||||
add(Reason::Spam, tr::lng_report_reason_spam, st::menuIconDelete);
|
||||
if (source != Source::Message) {
|
||||
if (source != Source::Message && !isProfileSource) {
|
||||
add(Reason::Fake, tr::lng_report_reason_fake, st::menuIconFake);
|
||||
}
|
||||
add(
|
||||
|
||||
@@ -16,6 +16,8 @@ enum class ReportSource {
|
||||
Channel,
|
||||
Group,
|
||||
Bot,
|
||||
ProfilePhoto,
|
||||
ProfileVideo,
|
||||
};
|
||||
|
||||
enum class ReportReason {
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/event_filter.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/effects/animation_value.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/widgets/vertical_drum_picker.h"
|
||||
#include "styles/style_chat.h"
|
||||
@@ -17,6 +18,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Ui {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMinYScale = 0.2;
|
||||
|
||||
} // namespace
|
||||
|
||||
Fn<TimeId()> TimePickerBox(
|
||||
not_null<GenericBox*> box,
|
||||
std::vector<TimeId> values,
|
||||
@@ -24,9 +31,17 @@ Fn<TimeId()> TimePickerBox(
|
||||
TimeId startValue) {
|
||||
Expects(phrases.size() == values.size());
|
||||
|
||||
const auto startIndex = [&] {
|
||||
const auto it = ranges::find(values, startValue);
|
||||
return (it == end(values)) ? 0 : std::distance(begin(values), it);
|
||||
const auto startIndex = [&, &v = startValue] {
|
||||
const auto it = ranges::lower_bound(values, v);
|
||||
if (it == begin(values)) {
|
||||
return 0;
|
||||
}
|
||||
const auto left = *(it - 1);
|
||||
const auto right = *it;
|
||||
const auto shift = (std::abs(v - left) < std::abs(v - right))
|
||||
? -1
|
||||
: 0;
|
||||
return int(std::distance(begin(values), it - shift));
|
||||
}();
|
||||
|
||||
const auto content = box->addRow(object_ptr<Ui::FixedHeightWidget>(
|
||||
@@ -35,11 +50,14 @@ Fn<TimeId()> TimePickerBox(
|
||||
|
||||
const auto font = st::boxTextFont;
|
||||
const auto maxPhraseWidth = [&] {
|
||||
// We have to use QFontMetricsF instead of
|
||||
// FontData::width for more precise calculation.
|
||||
const auto mf = QFontMetricsF(font->f);
|
||||
const auto maxPhrase = ranges::max_element(
|
||||
phrases,
|
||||
std::less<>(),
|
||||
[&](const QString &s) { return font->width(s); });
|
||||
return font->width(*maxPhrase) + font->spacew * 2;
|
||||
[&](const QString &s) { return mf.horizontalAdvance(s); });
|
||||
return std::ceil(mf.horizontalAdvance(*maxPhrase));
|
||||
}();
|
||||
const auto itemHeight = st::historyMessagesTTLPickerItemHeight;
|
||||
auto paintCallback = [=](
|
||||
@@ -50,10 +68,18 @@ Fn<TimeId()> TimePickerBox(
|
||||
int outerWidth) {
|
||||
const auto r = QRectF(0, y, outerWidth, itemHeight);
|
||||
const auto progress = std::abs(distanceFromCenter);
|
||||
p.setOpacity(1. - progress);
|
||||
const auto revProgress = 1. - progress;
|
||||
p.save();
|
||||
p.translate(r.center());
|
||||
const auto yScale = kMinYScale
|
||||
+ (1. - kMinYScale) * anim::easeOutCubic(1., revProgress);
|
||||
p.scale(1., yScale);
|
||||
p.translate(-r.center());
|
||||
p.setOpacity(revProgress);
|
||||
p.setFont(font);
|
||||
p.setPen(st::defaultFlatLabel.textFg);
|
||||
p.drawText(r, phrases[index], style::al_center);
|
||||
p.restore();
|
||||
};
|
||||
|
||||
const auto picker = Ui::CreateChild<Ui::VerticalDrumPicker>(
|
||||
|
||||
@@ -322,7 +322,9 @@ Panel::Panel(
|
||||
_widget->closeEvents(
|
||||
) | rpl::start_with_next(_close, _widget->lifetime());
|
||||
|
||||
style::PaletteChanged(
|
||||
rpl::combine(
|
||||
style::PaletteChanged(),
|
||||
_themeUpdateForced.events()
|
||||
) | rpl::filter([=] {
|
||||
return !_themeUpdateScheduled;
|
||||
}) | rpl::start_with_next([=] {
|
||||
@@ -564,6 +566,8 @@ bool Panel::createWebview() {
|
||||
sendDataMessage(list.at(1));
|
||||
} else if (command == "web_app_setup_main_button") {
|
||||
processMainButtonMessage(list.at(1));
|
||||
} else if (command == "web_app_request_theme") {
|
||||
_themeUpdateForced.fire({});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ private:
|
||||
QPointer<QWidget> _webviewParent;
|
||||
std::unique_ptr<Button> _mainButton;
|
||||
std::unique_ptr<Progress> _progress;
|
||||
rpl::event_stream<> _themeUpdateForced;
|
||||
rpl::lifetime _fgLifetime;
|
||||
rpl::lifetime _bgLifetime;
|
||||
bool _webviewProgress = false;
|
||||
|
||||
@@ -325,7 +325,8 @@ historyMessagesTTL: IconButtonWithText {
|
||||
}
|
||||
textFg: historyComposeIconFg;
|
||||
textFgOver: historyComposeIconFgOver;
|
||||
textPadding: margins(16px, 20px, 6px, 7px);
|
||||
textPadding: margins(21px, 20px, 3px, 7px);
|
||||
textAlign: align(left);
|
||||
|
||||
font: font(10px semibold);
|
||||
}
|
||||
@@ -476,6 +477,13 @@ historyPinnedShowAll: IconButton(historyReplyCancel) {
|
||||
icon: icon {{ "pinned_show_all", historyReplyCancelFg }};
|
||||
iconOver: icon {{ "pinned_show_all", historyReplyCancelFgOver }};
|
||||
}
|
||||
historyPinnedBotButton: RoundButton(defaultActiveButton) {
|
||||
width: -34px;
|
||||
height: 30px;
|
||||
textTop: 6px;
|
||||
padding: margins(2px, 10px, 10px, 9px);
|
||||
}
|
||||
historyPinnedBotButtonMaxWidth: 150px;
|
||||
|
||||
msgBotKbDuration: 200;
|
||||
msgBotKbFont: semiboldFont;
|
||||
|
||||
@@ -222,7 +222,7 @@ QRect MessageBar::bodyRect(bool withImage) const {
|
||||
const auto top = st::msgReplyPadding.top();
|
||||
const auto width = _widget.width() - left - st::msgReplyPadding.right();
|
||||
const auto height = st::msgReplyBarSize.height();
|
||||
return QRect(left, top, width, height);
|
||||
return QRect(left, top, width, height) - _content.margins;
|
||||
}
|
||||
|
||||
QRect MessageBar::bodyRect() const {
|
||||
|
||||
@@ -24,6 +24,7 @@ struct MessageBarContent {
|
||||
QString title;
|
||||
TextWithEntities text;
|
||||
QImage preview;
|
||||
style::margins margins;
|
||||
};
|
||||
|
||||
class MessageBar final {
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/chat/message_bar.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/palette.h"
|
||||
|
||||
@@ -17,9 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Ui {
|
||||
|
||||
PinnedBar::PinnedBar(
|
||||
not_null<QWidget*> parent,
|
||||
rpl::producer<MessageBarContent> content)
|
||||
PinnedBar::PinnedBar(not_null<QWidget*> parent)
|
||||
: _wrap(parent, object_ptr<RpWidget>(parent))
|
||||
, _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget())) {
|
||||
_wrap.hide(anim::type::instant);
|
||||
@@ -30,10 +29,18 @@ PinnedBar::PinnedBar(
|
||||
QPainter(_wrap.entity()).fillRect(clip, st::historyPinnedBg);
|
||||
}, lifetime());
|
||||
_wrap.setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
}
|
||||
|
||||
PinnedBar::~PinnedBar() {
|
||||
_right.button.destroy();
|
||||
}
|
||||
|
||||
void PinnedBar::setContent(rpl::producer<Ui::MessageBarContent> content) {
|
||||
_contentLifetime.destroy();
|
||||
|
||||
auto copy = std::move(
|
||||
content
|
||||
) | rpl::start_spawning(_wrap.lifetime());
|
||||
) | rpl::start_spawning(_contentLifetime);
|
||||
|
||||
rpl::duplicate(
|
||||
copy
|
||||
@@ -44,11 +51,17 @@ PinnedBar::PinnedBar(
|
||||
if (creating) {
|
||||
createControls();
|
||||
}
|
||||
|
||||
// In most cases the new right button should arrive
|
||||
// before we want to get its width.
|
||||
const auto right = _right.button ? _right.button->width() : 0;
|
||||
content.margins = { 0, 0, right, 0 };
|
||||
|
||||
_bar->set(std::move(content));
|
||||
if (creating) {
|
||||
_bar->finishAnimating();
|
||||
}
|
||||
}, lifetime());
|
||||
}, _contentLifetime);
|
||||
|
||||
std::move(
|
||||
copy
|
||||
@@ -64,19 +77,24 @@ PinnedBar::PinnedBar(
|
||||
}, [=] {
|
||||
_forceHidden = true;
|
||||
_wrap.toggle(false, anim::type::normal);
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
PinnedBar::~PinnedBar() {
|
||||
_rightButton.destroy();
|
||||
}, _contentLifetime);
|
||||
}
|
||||
|
||||
void PinnedBar::setRightButton(object_ptr<Ui::RpWidget> button) {
|
||||
_rightButton.destroy();
|
||||
_rightButton = std::move(button);
|
||||
if (_rightButton) {
|
||||
_rightButton->setParent(_wrap.entity());
|
||||
_rightButton->show();
|
||||
if (auto previous = _right.button.release()) {
|
||||
_right.previousButtonLifetime.make_state<RightButton>(
|
||||
RightButton::fromRaw(std::move(previous)));
|
||||
_right.previousButtonLifetime = previous->toggledValue(
|
||||
) | rpl::filter(!rpl::mappers::_1) | rpl::start_with_next([=] {
|
||||
_right.previousButtonLifetime.destroy();
|
||||
});
|
||||
previous->hide(anim::type::normal);
|
||||
}
|
||||
_right.button.create(_wrap.entity(), std::move(button));
|
||||
if (_right.button) {
|
||||
_right.button->setParent(_wrap.entity());
|
||||
_right.button->setDuration(st::defaultMessageBar.duration);
|
||||
_right.button->show(anim::type::normal);
|
||||
}
|
||||
if (_bar) {
|
||||
updateControlsGeometry(_wrap.geometry());
|
||||
@@ -84,14 +102,13 @@ void PinnedBar::setRightButton(object_ptr<Ui::RpWidget> button) {
|
||||
}
|
||||
|
||||
void PinnedBar::updateControlsGeometry(QRect wrapGeometry) {
|
||||
_bar->widget()->resizeToWidth(
|
||||
wrapGeometry.width() - (_rightButton ? _rightButton->width() : 0));
|
||||
_bar->widget()->resizeToWidth(wrapGeometry.width());
|
||||
const auto hidden = _wrap.isHidden() || !wrapGeometry.height();
|
||||
if (_shadow->isHidden() != hidden) {
|
||||
_shadow->setVisible(!hidden);
|
||||
}
|
||||
if (_rightButton) {
|
||||
_rightButton->moveToRight(0, 0);
|
||||
if (_right.button) {
|
||||
_right.button->moveToRight(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,8 +134,8 @@ void PinnedBar::createControls() {
|
||||
_bar = std::make_unique<MessageBar>(
|
||||
_wrap.entity(),
|
||||
st::defaultMessageBar);
|
||||
if (_rightButton) {
|
||||
_rightButton->raise();
|
||||
if (_right.button) {
|
||||
_right.button->raise();
|
||||
}
|
||||
|
||||
// Clicks.
|
||||
|
||||
@@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Ui {
|
||||
|
||||
struct MessageBarContent;
|
||||
template <typename Widget>
|
||||
class FadeWrapScaled;
|
||||
class MessageBar;
|
||||
class IconButton;
|
||||
class PlainShadow;
|
||||
@@ -20,9 +22,7 @@ class RpWidget;
|
||||
|
||||
class PinnedBar final {
|
||||
public:
|
||||
PinnedBar(
|
||||
not_null<QWidget*> parent,
|
||||
rpl::producer<Ui::MessageBarContent> content);
|
||||
PinnedBar(not_null<QWidget*> parent);
|
||||
~PinnedBar();
|
||||
|
||||
void show();
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
|
||||
void setShadowGeometryPostprocess(Fn<QRect(QRect)> postprocess);
|
||||
|
||||
void setContent(rpl::producer<Ui::MessageBarContent> content);
|
||||
void setRightButton(object_ptr<Ui::RpWidget> button);
|
||||
|
||||
void move(int x, int y);
|
||||
@@ -45,19 +46,27 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
using RightButton = object_ptr<Ui::FadeWrapScaled<Ui::RpWidget>>;
|
||||
void createControls();
|
||||
void updateShadowGeometry(QRect wrapGeometry);
|
||||
void updateControlsGeometry(QRect wrapGeometry);
|
||||
|
||||
Ui::SlideWrap<> _wrap;
|
||||
std::unique_ptr<Ui::MessageBar> _bar;
|
||||
object_ptr<Ui::RpWidget> _rightButton = { nullptr };
|
||||
|
||||
struct {
|
||||
RightButton button = { nullptr };
|
||||
rpl::lifetime previousButtonLifetime;
|
||||
} _right;
|
||||
|
||||
std::unique_ptr<Ui::PlainShadow> _shadow;
|
||||
rpl::event_stream<> _barClicks;
|
||||
Fn<QRect(QRect)> _shadowGeometryPostprocess;
|
||||
bool _shouldBeShown = false;
|
||||
bool _forceHidden = false;
|
||||
|
||||
rpl::lifetime _contentLifetime;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Ui
|
||||
|
||||
@@ -131,6 +131,7 @@ mediaMenuIconForward: icon {{ "menu/forward", mediaviewMenuFg }};
|
||||
mediaMenuIconDelete: icon {{ "menu/delete", mediaviewMenuFg }};
|
||||
mediaMenuIconShowAll: icon {{ "menu/all_media", mediaviewMenuFg }};
|
||||
mediaMenuIconProfile: icon {{ "menu/profile", mediaviewMenuFg }};
|
||||
mediaMenuIconReport: icon {{ "menu/report", mediaviewMenuFg }};
|
||||
|
||||
menuIconStartStream: icon {{ "menu/start_stream", menuIconColor }};
|
||||
menuIconStartStreamWith: icon {{ "menu/start_stream_with", menuIconColor }};
|
||||
|
||||
@@ -386,33 +386,33 @@ QString FormatPhone(const QString &phone) {
|
||||
|
||||
QString FormatTTL(float64 ttl) {
|
||||
return (ttl <= 3600 * 23)
|
||||
? tr::lng_hours(tr::now, lt_count, std::ceil(ttl / 3600))
|
||||
? tr::lng_hours(tr::now, lt_count, int(ttl / 3600))
|
||||
: (ttl <= (86400) * 6)
|
||||
? tr::lng_days(tr::now, lt_count, std::ceil(ttl / (86400)))
|
||||
? tr::lng_days(tr::now, lt_count, int(ttl / (86400)))
|
||||
: (ttl <= (86400 * 7) * 3)
|
||||
? tr::lng_weeks(tr::now, lt_count, std::ceil(ttl / (86400 * 7)))
|
||||
: (ttl <= (86400 * 30) * 11)
|
||||
? tr::lng_months({}, lt_count, std::ceil(ttl / (86400 * 30)))
|
||||
: tr::lng_years({}, lt_count, std::ceil(ttl / (86400 * 30 * 12)));
|
||||
? tr::lng_weeks(tr::now, lt_count, int(ttl / (86400 * 7)))
|
||||
: (ttl <= (86400 * 31) * 11)
|
||||
? tr::lng_months({}, lt_count, int(ttl / (86400 * 31)))
|
||||
: tr::lng_years({}, lt_count, std::round(ttl / (86400 * 365)));
|
||||
}
|
||||
|
||||
QString FormatTTLTiny(float64 ttl) {
|
||||
return (ttl <= 3600 * 9)
|
||||
? tr::lng_hours_tiny(tr::now, lt_count, std::ceil(ttl / 3600))
|
||||
? tr::lng_hours_tiny(tr::now, lt_count, int(ttl / 3600))
|
||||
: (ttl <= (86400) * 6)
|
||||
? tr::lng_days_tiny(tr::now, lt_count, std::ceil(ttl / (86400)))
|
||||
? tr::lng_days_tiny(tr::now, lt_count, int(ttl / (86400)))
|
||||
: (ttl <= (86400 * 7) * 3)
|
||||
? tr::lng_weeks_tiny(tr::now, lt_count, std::ceil(ttl / (86400 * 7)))
|
||||
: (ttl <= (86400 * 30) * 11)
|
||||
? tr::lng_months_tiny({}, lt_count, std::ceil(ttl / (86400 * 30)))
|
||||
: tr::lng_years_tiny({}, lt_count, std::ceil(ttl / (86400 * 360)));
|
||||
? tr::lng_weeks_tiny(tr::now, lt_count, int(ttl / (86400 * 7)))
|
||||
: (ttl <= (86400 * 31) * 11)
|
||||
? tr::lng_months_tiny({}, lt_count, int(ttl / (86400 * 31)))
|
||||
: tr::lng_years_tiny({}, lt_count, std::round(ttl / (86400 * 365)));
|
||||
}
|
||||
|
||||
QString FormatMuteFor(float64 sec) {
|
||||
return (sec <= 60)
|
||||
? tr::lng_seconds(tr::now, lt_count, sec)
|
||||
: (sec <= 60 * 59)
|
||||
? tr::lng_minutes(tr::now, lt_count, std::ceil(sec / 60))
|
||||
? tr::lng_minutes(tr::now, lt_count, int(sec / 60))
|
||||
: FormatTTL(sec);
|
||||
}
|
||||
|
||||
@@ -420,13 +420,13 @@ QString FormatMuteForTiny(float64 sec) {
|
||||
return (sec <= 60)
|
||||
? QString()
|
||||
: (sec <= 60 * 59)
|
||||
? tr::lng_minutes_tiny(tr::now, lt_count, std::ceil(sec / 60))
|
||||
? tr::lng_minutes_tiny(tr::now, lt_count, int(sec / 60))
|
||||
: (sec <= 3600 * 23)
|
||||
? tr::lng_hours_tiny(tr::now, lt_count, std::ceil(sec / 3600))
|
||||
? tr::lng_hours_tiny(tr::now, lt_count, int(sec / 3600))
|
||||
: (sec <= 86400 * 6)
|
||||
? tr::lng_days_tiny(tr::now, lt_count, std::ceil(sec / 86400))
|
||||
? tr::lng_days_tiny(tr::now, lt_count, int(sec / 86400))
|
||||
: (sec <= (86400 * 7) * 3)
|
||||
? tr::lng_weeks_tiny(tr::now, lt_count, std::ceil(sec / (86400 * 7)))
|
||||
? tr::lng_weeks_tiny(tr::now, lt_count, int(sec / (86400 * 7)))
|
||||
: QString();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,15 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "ui/widgets/multi_select.h"
|
||||
|
||||
#include "styles/style_widgets.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/cross_animation.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace Ui {
|
||||
namespace {
|
||||
|
||||
|
||||