mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Implement nice tag edit with preview.
This commit is contained in:
@@ -228,6 +228,8 @@ PRIVATE
|
|||||||
boxes/peers/edit_members_visible.h
|
boxes/peers/edit_members_visible.h
|
||||||
boxes/peers/edit_participant_box.cpp
|
boxes/peers/edit_participant_box.cpp
|
||||||
boxes/peers/edit_participant_box.h
|
boxes/peers/edit_participant_box.h
|
||||||
|
boxes/peers/edit_tag_control.cpp
|
||||||
|
boxes/peers/edit_tag_control.h
|
||||||
boxes/peers/edit_participants_box.cpp
|
boxes/peers/edit_participants_box.cpp
|
||||||
boxes/peers/edit_participants_box.h
|
boxes/peers/edit_participants_box.h
|
||||||
boxes/peers/edit_peer_color_box.cpp
|
boxes/peers/edit_peer_color_box.cpp
|
||||||
|
|||||||
@@ -852,6 +852,10 @@ customBadgeField: InputField(defaultInputField) {
|
|||||||
heightMin: 32px;
|
heightMin: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tagPreviewLineHeight: 8px;
|
||||||
|
tagPreviewLineSpacing: 4px;
|
||||||
|
tagPreviewInputSkip: 16px;
|
||||||
|
|
||||||
pollResultsQuestion: FlatLabel(defaultFlatLabel) {
|
pollResultsQuestion: FlatLabel(defaultFlatLabel) {
|
||||||
minWidth: 320px;
|
minWidth: 320px;
|
||||||
textFg: windowBoldFg;
|
textFg: windowBoldFg;
|
||||||
|
|||||||
@@ -1582,6 +1582,7 @@ void AddSpecialBoxController::showRestricted(
|
|||||||
user,
|
user,
|
||||||
_additional.adminRights(user).has_value(),
|
_additional.adminRights(user).has_value(),
|
||||||
currentRights,
|
currentRights,
|
||||||
|
_additional.memberRank(user),
|
||||||
_additional.restrictedBy(user),
|
_additional.restrictedBy(user),
|
||||||
_additional.restrictedSince(user));
|
_additional.restrictedSince(user));
|
||||||
if (_additional.canRestrictParticipant(user)) {
|
if (_additional.canRestrictParticipant(user)) {
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
*/
|
*/
|
||||||
#include "boxes/peers/edit_participant_box.h"
|
#include "boxes/peers/edit_participant_box.h"
|
||||||
|
|
||||||
|
#include "boxes/peers/edit_tag_control.h"
|
||||||
|
#include "boxes/peers/edit_participants_box.h"
|
||||||
|
#include "history/view/history_view_message.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "ui/controls/userpic_button.h"
|
#include "ui/controls/userpic_button.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
@@ -47,7 +50,64 @@ namespace {
|
|||||||
constexpr auto kMaxRestrictDelayDays = 366;
|
constexpr auto kMaxRestrictDelayDays = 366;
|
||||||
constexpr auto kSecondsInDay = 24 * 60 * 60;
|
constexpr auto kSecondsInDay = 24 * 60 * 60;
|
||||||
constexpr auto kSecondsInWeek = 7 * kSecondsInDay;
|
constexpr auto kSecondsInWeek = 7 * kSecondsInDay;
|
||||||
constexpr auto kAdminRoleLimit = 16;
|
|
||||||
|
class Cover final : public Ui::FixedHeightWidget {
|
||||||
|
public:
|
||||||
|
Cover(QWidget *parent, not_null<UserData*> user, bool hasAdminRights);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupChildGeometry();
|
||||||
|
|
||||||
|
const style::InfoProfileCover &_st;
|
||||||
|
const not_null<UserData*> _user;
|
||||||
|
object_ptr<Ui::UserpicButton> _userpic;
|
||||||
|
object_ptr<Ui::FlatLabel> _name = { nullptr };
|
||||||
|
object_ptr<Ui::FlatLabel> _status = { nullptr };
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Cover::Cover(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<UserData*> user,
|
||||||
|
bool hasAdminRights)
|
||||||
|
: FixedHeightWidget(parent, st::infoEditContactCover.height)
|
||||||
|
, _st(st::infoEditContactCover)
|
||||||
|
, _user(user)
|
||||||
|
, _userpic(this, _user, _st.photo) {
|
||||||
|
_userpic->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
|
||||||
|
_name = object_ptr<Ui::FlatLabel>(this, _st.name);
|
||||||
|
_name->setText(_user->name());
|
||||||
|
|
||||||
|
const auto statusText = [&] {
|
||||||
|
if (_user->isBot()) {
|
||||||
|
const auto seesAllMessages = _user->botInfo->readsAllHistory
|
||||||
|
|| hasAdminRights;
|
||||||
|
return (seesAllMessages
|
||||||
|
? tr::lng_status_bot_reads_all
|
||||||
|
: tr::lng_status_bot_not_reads_all)(tr::now);
|
||||||
|
}
|
||||||
|
return Data::OnlineText(_user->lastseen(), base::unixtime::now());
|
||||||
|
}();
|
||||||
|
_status = object_ptr<Ui::FlatLabel>(this, _st.status);
|
||||||
|
_status->setText(statusText);
|
||||||
|
_status->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
|
||||||
|
setupChildGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cover::setupChildGeometry() {
|
||||||
|
widthValue(
|
||||||
|
) | rpl::on_next([this](int newWidth) {
|
||||||
|
_userpic->moveToLeft(_st.photoLeft, _st.photoTop, newWidth);
|
||||||
|
auto nameWidth = newWidth - _st.nameLeft - _st.rightSkip;
|
||||||
|
_name->resizeToNaturalWidth(nameWidth);
|
||||||
|
_name->moveToLeft(_st.nameLeft, _st.nameTop, newWidth);
|
||||||
|
auto statusWidth = newWidth - _st.statusLeft - _st.rightSkip;
|
||||||
|
_status->resizeToNaturalWidth(statusWidth);
|
||||||
|
_status->moveToLeft(_st.statusLeft, _st.statusTop, newWidth);
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -66,6 +126,8 @@ public:
|
|||||||
return _rows;
|
return _rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCoverMode(bool enabled);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int resizeGetHeight(int newWidth) override;
|
int resizeGetHeight(int newWidth) override;
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
@@ -76,6 +138,7 @@ private:
|
|||||||
object_ptr<Ui::UserpicButton> _userPhoto;
|
object_ptr<Ui::UserpicButton> _userPhoto;
|
||||||
Ui::Text::String _userName;
|
Ui::Text::String _userName;
|
||||||
bool _hasAdminRights = false;
|
bool _hasAdminRights = false;
|
||||||
|
bool _coverMode = false;
|
||||||
object_ptr<Ui::VerticalLayout> _rows;
|
object_ptr<Ui::VerticalLayout> _rows;
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -110,7 +173,20 @@ Widget *EditParticipantBox::Inner::addControl(
|
|||||||
return _rows->add(std::move(widget), margin);
|
return _rows->add(std::move(widget), margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditParticipantBox::Inner::setCoverMode(bool enabled) {
|
||||||
|
_coverMode = enabled;
|
||||||
|
if (enabled) {
|
||||||
|
_userPhoto->hide();
|
||||||
|
}
|
||||||
|
resizeToWidth(width());
|
||||||
|
}
|
||||||
|
|
||||||
int EditParticipantBox::Inner::resizeGetHeight(int newWidth) {
|
int EditParticipantBox::Inner::resizeGetHeight(int newWidth) {
|
||||||
|
if (_coverMode) {
|
||||||
|
_rows->resizeToWidth(newWidth);
|
||||||
|
_rows->moveToLeft(0, 0, newWidth);
|
||||||
|
return _rows->heightNoMargins();
|
||||||
|
}
|
||||||
_userPhoto->moveToLeft(
|
_userPhoto->moveToLeft(
|
||||||
st::rightsPhotoMargin.left(),
|
st::rightsPhotoMargin.left(),
|
||||||
st::rightsPhotoMargin.top());
|
st::rightsPhotoMargin.top());
|
||||||
@@ -127,6 +203,10 @@ void EditParticipantBox::Inner::paintEvent(QPaintEvent *e) {
|
|||||||
|
|
||||||
p.fillRect(e->rect(), st::boxBg);
|
p.fillRect(e->rect(), st::boxBg);
|
||||||
|
|
||||||
|
if (_coverMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
p.setPen(st::contactsNameFg);
|
p.setPen(st::contactsNameFg);
|
||||||
auto namex = st::rightsPhotoMargin.left()
|
auto namex = st::rightsPhotoMargin.left()
|
||||||
+ st::rightsPhotoButton.size .width()
|
+ st::rightsPhotoButton.size .width()
|
||||||
@@ -198,6 +278,12 @@ bool EditParticipantBox::amCreator() const {
|
|||||||
Unexpected("Peer type in EditParticipantBox::Inner::amCreator.");
|
Unexpected("Peer type in EditParticipantBox::Inner::amCreator.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditParticipantBox::setCoverMode(bool enabled) {
|
||||||
|
Expects(_inner != nullptr);
|
||||||
|
|
||||||
|
_inner->setCoverMode(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
EditAdminBox::EditAdminBox(
|
EditAdminBox::EditAdminBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
@@ -255,6 +341,11 @@ void EditAdminBox::prepare() {
|
|||||||
|
|
||||||
EditParticipantBox::prepare();
|
EditParticipantBox::prepare();
|
||||||
|
|
||||||
|
setCoverMode(true);
|
||||||
|
addControl(
|
||||||
|
object_ptr<Cover>(this, user(), hasAdminRights()),
|
||||||
|
style::margins());
|
||||||
|
|
||||||
setTitle(_addingBot
|
setTitle(_addingBot
|
||||||
? (_addingBot->existing
|
? (_addingBot->existing
|
||||||
? tr::lng_rights_edit_admin()
|
? tr::lng_rights_edit_admin()
|
||||||
@@ -433,7 +524,17 @@ void EditAdminBox::prepare() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (canSave()) {
|
if (canSave()) {
|
||||||
_rank = hasRank ? addRankInput(inner).get() : nullptr;
|
if (hasRank) {
|
||||||
|
const auto role = LookupBadgeRole(peer(), user());
|
||||||
|
_tagControl = inner->add(
|
||||||
|
object_ptr<EditTagControl>(
|
||||||
|
inner,
|
||||||
|
&peer()->session(),
|
||||||
|
user(),
|
||||||
|
_oldRank,
|
||||||
|
role),
|
||||||
|
style::margins());
|
||||||
|
}
|
||||||
_finishSave = [=, value = getChecked] {
|
_finishSave = [=, value = getChecked] {
|
||||||
const auto newFlags = (value() | ChatAdminRight::Other)
|
const auto newFlags = (value() | ChatAdminRight::Other)
|
||||||
& ((!channel || channel->amCreator())
|
& ((!channel || channel->amCreator())
|
||||||
@@ -442,7 +543,9 @@ void EditAdminBox::prepare() {
|
|||||||
_saveCallback(
|
_saveCallback(
|
||||||
_oldRights,
|
_oldRights,
|
||||||
ChatAdminRightsInfo(newFlags),
|
ChatAdminRightsInfo(newFlags),
|
||||||
_rank ? _rank->getLastText().trimmed() : QString());
|
_tagControl
|
||||||
|
? _tagControl->currentRank()
|
||||||
|
: QString());
|
||||||
};
|
};
|
||||||
_save = [=] {
|
_save = [=] {
|
||||||
const auto show = uiShow();
|
const auto show = uiShow();
|
||||||
@@ -497,56 +600,6 @@ void EditAdminBox::refreshButtons() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Ui::InputField*> EditAdminBox::addRankInput(
|
|
||||||
not_null<Ui::VerticalLayout*> container) {
|
|
||||||
// Ui::AddDivider(container);
|
|
||||||
|
|
||||||
container->add(
|
|
||||||
object_ptr<Ui::FlatLabel>(
|
|
||||||
container,
|
|
||||||
tr::lng_rights_edit_admin_rank_name(),
|
|
||||||
st::rightsHeaderLabel),
|
|
||||||
st::rightsHeaderMargin);
|
|
||||||
|
|
||||||
const auto isOwner = [&] {
|
|
||||||
if (user()->isSelf() && amCreator()) {
|
|
||||||
return true;
|
|
||||||
} else if (const auto chat = peer()->asChat()) {
|
|
||||||
return chat->creator == peerToUser(user()->id);
|
|
||||||
} else if (const auto channel = peer()->asChannel()) {
|
|
||||||
return channel->mgInfo && channel->mgInfo->creator == user();
|
|
||||||
}
|
|
||||||
Unexpected("Peer type in EditAdminBox::addRankInput.");
|
|
||||||
}();
|
|
||||||
const auto result = container->add(
|
|
||||||
object_ptr<Ui::InputField>(
|
|
||||||
container,
|
|
||||||
st::customBadgeField,
|
|
||||||
(isOwner ? tr::lng_owner_badge : tr::lng_admin_badge)(),
|
|
||||||
TextUtilities::RemoveEmoji(_oldRank)),
|
|
||||||
st::rightsAboutMargin);
|
|
||||||
result->setMaxLength(kAdminRoleLimit);
|
|
||||||
result->setInstantReplaces(Ui::InstantReplaces::TextOnly());
|
|
||||||
result->changes(
|
|
||||||
) | rpl::on_next([=] {
|
|
||||||
const auto text = result->getLastText();
|
|
||||||
const auto removed = TextUtilities::RemoveEmoji(text);
|
|
||||||
if (removed != text) {
|
|
||||||
result->setText(removed);
|
|
||||||
}
|
|
||||||
}, result->lifetime());
|
|
||||||
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
Ui::AddDividerText(
|
|
||||||
container,
|
|
||||||
tr::lng_rights_edit_admin_rank_about(
|
|
||||||
lt_title,
|
|
||||||
(isOwner ? tr::lng_owner_badge : tr::lng_admin_badge)()));
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EditAdminBox::canTransferOwnership() const {
|
bool EditAdminBox::canTransferOwnership() const {
|
||||||
if (user()->isInaccessible() || user()->isBot() || user()->isSelf()) {
|
if (user()->isInaccessible() || user()->isBot() || user()->isSelf()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -599,10 +652,12 @@ EditRestrictedBox::EditRestrictedBox(
|
|||||||
not_null<UserData*> user,
|
not_null<UserData*> user,
|
||||||
bool hasAdminRights,
|
bool hasAdminRights,
|
||||||
ChatRestrictionsInfo rights,
|
ChatRestrictionsInfo rights,
|
||||||
|
const QString &rank,
|
||||||
UserData *by,
|
UserData *by,
|
||||||
TimeId since)
|
TimeId since)
|
||||||
: EditParticipantBox(nullptr, peer, user, hasAdminRights)
|
: EditParticipantBox(nullptr, peer, user, hasAdminRights)
|
||||||
, _oldRights(rights)
|
, _oldRights(rights)
|
||||||
|
, _oldRank(rank)
|
||||||
, _by(by)
|
, _by(by)
|
||||||
, _since(since) {
|
, _since(since) {
|
||||||
}
|
}
|
||||||
@@ -613,6 +668,11 @@ void EditRestrictedBox::prepare() {
|
|||||||
|
|
||||||
EditParticipantBox::prepare();
|
EditParticipantBox::prepare();
|
||||||
|
|
||||||
|
setCoverMode(true);
|
||||||
|
addControl(
|
||||||
|
object_ptr<Cover>(this, user(), hasAdminRights()),
|
||||||
|
style::margins());
|
||||||
|
|
||||||
setTitle(tr::lng_rights_user_restrictions());
|
setTitle(tr::lng_rights_user_restrictions());
|
||||||
|
|
||||||
Ui::AddDivider(verticalLayout());
|
Ui::AddDivider(verticalLayout());
|
||||||
@@ -661,6 +721,17 @@ void EditRestrictedBox::prepare() {
|
|||||||
{ .isForum = peer()->isForum() });
|
{ .isForum = peer()->isForum() });
|
||||||
addControl(std::move(checkboxes), QMargins());
|
addControl(std::move(checkboxes), QMargins());
|
||||||
|
|
||||||
|
if (canSave() && peer()->canManageRanks()) {
|
||||||
|
_tagControl = addControl(
|
||||||
|
object_ptr<EditTagControl>(
|
||||||
|
this,
|
||||||
|
&peer()->session(),
|
||||||
|
user(),
|
||||||
|
_oldRank,
|
||||||
|
HistoryView::BadgeRole::User),
|
||||||
|
style::margins());
|
||||||
|
}
|
||||||
|
|
||||||
_until = prepareRights.until;
|
_until = prepareRights.until;
|
||||||
addControl(
|
addControl(
|
||||||
object_ptr<Ui::FixedHeightWidget>(this, st::defaultVerticalListSkip));
|
object_ptr<Ui::FixedHeightWidget>(this, st::defaultVerticalListSkip));
|
||||||
@@ -710,6 +781,18 @@ void EditRestrictedBox::prepare() {
|
|||||||
_saveCallback(
|
_saveCallback(
|
||||||
_oldRights,
|
_oldRights,
|
||||||
ChatRestrictionsInfo{ value(), getRealUntilValue() });
|
ChatRestrictionsInfo{ value(), getRealUntilValue() });
|
||||||
|
if (_tagControl) {
|
||||||
|
const auto rank = _tagControl->currentRank();
|
||||||
|
if (rank != _oldRank) {
|
||||||
|
SaveMemberRank(
|
||||||
|
uiShow(),
|
||||||
|
peer(),
|
||||||
|
user(),
|
||||||
|
rank,
|
||||||
|
nullptr,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
addButton(tr::lng_settings_save(), save);
|
addButton(tr::lng_settings_save(), save);
|
||||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class SlideWrap;
|
|||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class ChannelOwnershipTransfer;
|
class ChannelOwnershipTransfer;
|
||||||
|
class EditTagControl;
|
||||||
|
|
||||||
class EditParticipantBox : public Ui::BoxContent {
|
class EditParticipantBox : public Ui::BoxContent {
|
||||||
public:
|
public:
|
||||||
@@ -48,6 +49,8 @@ protected:
|
|||||||
template <typename Widget>
|
template <typename Widget>
|
||||||
Widget *addControl(object_ptr<Widget> widget, QMargins margin = {});
|
Widget *addControl(object_ptr<Widget> widget, QMargins margin = {});
|
||||||
|
|
||||||
|
void setCoverMode(bool enabled);
|
||||||
|
|
||||||
bool hasAdminRights() const {
|
bool hasAdminRights() const {
|
||||||
return _hasAdminRights;
|
return _hasAdminRights;
|
||||||
}
|
}
|
||||||
@@ -93,8 +96,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
[[nodiscard]] ChatAdminRightsInfo defaultRights() const;
|
[[nodiscard]] ChatAdminRightsInfo defaultRights() const;
|
||||||
|
|
||||||
not_null<Ui::InputField*> addRankInput(
|
|
||||||
not_null<Ui::VerticalLayout*> container);
|
|
||||||
void transferOwnership();
|
void transferOwnership();
|
||||||
bool canSave() const {
|
bool canSave() const {
|
||||||
return _saveCallback != nullptr;
|
return _saveCallback != nullptr;
|
||||||
@@ -116,7 +117,7 @@ private:
|
|||||||
base::weak_qptr<Ui::BoxContent> _confirmBox;
|
base::weak_qptr<Ui::BoxContent> _confirmBox;
|
||||||
Ui::Checkbox *_addAsAdmin = nullptr;
|
Ui::Checkbox *_addAsAdmin = nullptr;
|
||||||
Ui::SlideWrap<Ui::VerticalLayout> *_adminControlsWrap = nullptr;
|
Ui::SlideWrap<Ui::VerticalLayout> *_adminControlsWrap = nullptr;
|
||||||
Ui::InputField *_rank = nullptr;
|
EditTagControl *_tagControl = nullptr;
|
||||||
|
|
||||||
Fn<void()> _save, _finishSave;
|
Fn<void()> _save, _finishSave;
|
||||||
|
|
||||||
@@ -139,6 +140,7 @@ public:
|
|||||||
not_null<UserData*> user,
|
not_null<UserData*> user,
|
||||||
bool hasAdminRights,
|
bool hasAdminRights,
|
||||||
ChatRestrictionsInfo rights,
|
ChatRestrictionsInfo rights,
|
||||||
|
const QString &rank,
|
||||||
UserData *by,
|
UserData *by,
|
||||||
TimeId since);
|
TimeId since);
|
||||||
|
|
||||||
@@ -164,6 +166,8 @@ private:
|
|||||||
TimeId getRealUntilValue() const;
|
TimeId getRealUntilValue() const;
|
||||||
|
|
||||||
const ChatRestrictionsInfo _oldRights;
|
const ChatRestrictionsInfo _oldRights;
|
||||||
|
const QString _oldRank;
|
||||||
|
EditTagControl *_tagControl = nullptr;
|
||||||
UserData *_by = nullptr;
|
UserData *_by = nullptr;
|
||||||
TimeId _since = 0;
|
TimeId _since = 0;
|
||||||
TimeId _until = 0;
|
TimeId _until = 0;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
|
|
||||||
#include "api/api_chat_participants.h"
|
#include "api/api_chat_participants.h"
|
||||||
#include "boxes/peers/edit_participant_box.h"
|
#include "boxes/peers/edit_participant_box.h"
|
||||||
|
#include "boxes/peers/edit_tag_control.h"
|
||||||
#include "boxes/peers/add_participants_box.h"
|
#include "boxes/peers/add_participants_box.h"
|
||||||
#include "boxes/peers/prepare_short_info_box.h" // PrepareShortInfoBox
|
#include "boxes/peers/prepare_short_info_box.h" // PrepareShortInfoBox
|
||||||
#include "boxes/peers/edit_members_visible.h"
|
#include "boxes/peers/edit_members_visible.h"
|
||||||
@@ -39,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "info/profile/info_profile_values.h"
|
#include "info/profile/info_profile_values.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
#include "history/view/history_view_message.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
#include "styles/style_menu_icons.h"
|
#include "styles/style_menu_icons.h"
|
||||||
@@ -172,6 +174,29 @@ void SaveChannelAdmin(
|
|||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SaveChatParticipantKick(
|
||||||
|
not_null<ChatData*> chat,
|
||||||
|
not_null<UserData*> user,
|
||||||
|
Fn<void()> onDone,
|
||||||
|
Fn<void()> onFail) {
|
||||||
|
chat->session().api().request(MTPmessages_DeleteChatUser(
|
||||||
|
MTP_flags(0),
|
||||||
|
chat->inputChat(),
|
||||||
|
user->inputUser()
|
||||||
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
chat->session().api().applyUpdates(result);
|
||||||
|
if (onDone) {
|
||||||
|
onDone();
|
||||||
|
}
|
||||||
|
}).fail([=] {
|
||||||
|
if (onFail) {
|
||||||
|
onFail();
|
||||||
|
}
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void SaveMemberRank(
|
void SaveMemberRank(
|
||||||
std::shared_ptr<Ui::Show> show,
|
std::shared_ptr<Ui::Show> show,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
@@ -222,29 +247,6 @@ void SaveMemberRank(
|
|||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveChatParticipantKick(
|
|
||||||
not_null<ChatData*> chat,
|
|
||||||
not_null<UserData*> user,
|
|
||||||
Fn<void()> onDone,
|
|
||||||
Fn<void()> onFail) {
|
|
||||||
chat->session().api().request(MTPmessages_DeleteChatUser(
|
|
||||||
MTP_flags(0),
|
|
||||||
chat->inputChat(),
|
|
||||||
user->inputUser()
|
|
||||||
)).done([=](const MTPUpdates &result) {
|
|
||||||
chat->session().api().applyUpdates(result);
|
|
||||||
if (onDone) {
|
|
||||||
onDone();
|
|
||||||
}
|
|
||||||
}).fail([=] {
|
|
||||||
if (onFail) {
|
|
||||||
onFail();
|
|
||||||
}
|
|
||||||
}).send();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Fn<void(
|
Fn<void(
|
||||||
ChatAdminRightsInfo oldRights,
|
ChatAdminRightsInfo oldRights,
|
||||||
ChatAdminRightsInfo newRights,
|
ChatAdminRightsInfo newRights,
|
||||||
@@ -1993,6 +1995,7 @@ void ParticipantsBoxController::showRestricted(not_null<UserData*> user) {
|
|||||||
user,
|
user,
|
||||||
hasAdminRights,
|
hasAdminRights,
|
||||||
currentRights,
|
currentRights,
|
||||||
|
_additional.memberRank(user),
|
||||||
_additional.restrictedBy(user),
|
_additional.restrictedBy(user),
|
||||||
_additional.restrictedSince(user));
|
_additional.restrictedSince(user));
|
||||||
if (_additional.canRestrictParticipant(user)) {
|
if (_additional.canRestrictParticipant(user)) {
|
||||||
@@ -2662,7 +2665,6 @@ void EditCustomRankBox(
|
|||||||
const QString ¤tRank,
|
const QString ¤tRank,
|
||||||
bool isSelf,
|
bool isSelf,
|
||||||
Fn<void(QString rank)> onSaved) {
|
Fn<void(QString rank)> onSaved) {
|
||||||
constexpr auto kRankLimit = 16;
|
|
||||||
struct State {
|
struct State {
|
||||||
bool saving = false;
|
bool saving = false;
|
||||||
};
|
};
|
||||||
@@ -2677,21 +2679,16 @@ void EditCustomRankBox(
|
|||||||
? tr::lng_context_edit_member_tag()
|
? tr::lng_context_edit_member_tag()
|
||||||
: tr::lng_context_add_member_tag()));
|
: tr::lng_context_add_member_tag()));
|
||||||
|
|
||||||
const auto field = box->addRow(object_ptr<Ui::InputField>(
|
const auto role = LookupBadgeRole(peer, user);
|
||||||
box,
|
const auto control = box->addRow(
|
||||||
st::customBadgeField,
|
object_ptr<EditTagControl>(
|
||||||
tr::lng_rights_edit_admin_rank_name(),
|
box,
|
||||||
TextUtilities::RemoveEmoji(currentRank)));
|
&peer->session(),
|
||||||
field->setMaxLength(kRankLimit);
|
user,
|
||||||
field->setInstantReplaces(Ui::InstantReplaces::TextOnly());
|
currentRank,
|
||||||
field->changes(
|
role),
|
||||||
) | rpl::on_next([=] {
|
style::margins());
|
||||||
const auto text = field->getLastText();
|
const auto field = control->field();
|
||||||
const auto removed = TextUtilities::RemoveEmoji(text);
|
|
||||||
if (removed != text) {
|
|
||||||
field->setText(removed);
|
|
||||||
}
|
|
||||||
}, field->lifetime());
|
|
||||||
|
|
||||||
box->setFocusCallback([=] { field->setFocusFast(); });
|
box->setFocusCallback([=] { field->setFocusFast(); });
|
||||||
|
|
||||||
@@ -2701,8 +2698,7 @@ void EditCustomRankBox(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state->saving = true;
|
state->saving = true;
|
||||||
const auto rank = TextUtilities::RemoveEmoji(
|
const auto rank = control->currentRank();
|
||||||
TextUtilities::SingleLine(field->getLastText().trimmed()));
|
|
||||||
SaveMemberRank(
|
SaveMemberRank(
|
||||||
show,
|
show,
|
||||||
peer,
|
peer,
|
||||||
|
|||||||
@@ -58,6 +58,14 @@ void EditCustomRankBox(
|
|||||||
bool isSelf,
|
bool isSelf,
|
||||||
Fn<void(QString rank)> onSaved);
|
Fn<void(QString rank)> onSaved);
|
||||||
|
|
||||||
|
void SaveMemberRank(
|
||||||
|
std::shared_ptr<Ui::Show> show,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
not_null<UserData*> user,
|
||||||
|
const QString &rank,
|
||||||
|
Fn<void()> onDone,
|
||||||
|
Fn<void()> onFail);
|
||||||
|
|
||||||
void SubscribeToMigration(
|
void SubscribeToMigration(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
rpl::lifetime &lifetime,
|
rpl::lifetime &lifetime,
|
||||||
|
|||||||
@@ -0,0 +1,401 @@
|
|||||||
|
/*
|
||||||
|
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/peers/edit_tag_control.h"
|
||||||
|
|
||||||
|
#include "base/unixtime.h"
|
||||||
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_user.h"
|
||||||
|
#include "history/admin_log/history_admin_log_item.h"
|
||||||
|
#include "history/history.h"
|
||||||
|
#include "history/history_item.h"
|
||||||
|
#include "history/view/history_view_element.h"
|
||||||
|
#include "history/view/history_view_message.h"
|
||||||
|
#include "history/view/media/history_view_media_generic.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "ui/chat/chat_style.h"
|
||||||
|
#include "ui/chat/chat_theme.h"
|
||||||
|
#include "ui/effects/path_shift_gradient.h"
|
||||||
|
#include "ui/painter.h"
|
||||||
|
#include "ui/text/text_utilities.h"
|
||||||
|
#include "ui/widgets/fields/input_field.h"
|
||||||
|
#include "window/section_widget.h"
|
||||||
|
#include "window/themes/window_theme.h"
|
||||||
|
#include "styles/style_boxes.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
#include "styles/style_layers.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kRankLimit = 16;
|
||||||
|
constexpr auto kTextLinesAlpha = 0.1;
|
||||||
|
|
||||||
|
using namespace HistoryView;
|
||||||
|
|
||||||
|
class TextLinesPart final : public MediaGenericPart {
|
||||||
|
public:
|
||||||
|
TextLinesPart(QMargins margins);
|
||||||
|
|
||||||
|
void draw(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context,
|
||||||
|
int outerWidth) const override;
|
||||||
|
QSize countOptimalSize() override;
|
||||||
|
QSize countCurrentSize(int newWidth) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMargins _margins;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TextLinesPart::TextLinesPart(QMargins margins)
|
||||||
|
: _margins(margins) {
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize TextLinesPart::countOptimalSize() {
|
||||||
|
const auto h = _margins.top()
|
||||||
|
+ 4 * st::tagPreviewLineHeight
|
||||||
|
+ 3 * st::tagPreviewLineSpacing
|
||||||
|
+ _margins.bottom();
|
||||||
|
return { st::msgMinWidth, h };
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize TextLinesPart::countCurrentSize(int newWidth) {
|
||||||
|
return { newWidth, minHeight() };
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextLinesPart::draw(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context,
|
||||||
|
int outerWidth) const {
|
||||||
|
const auto &stm = context.messageStyle();
|
||||||
|
auto color = stm->historyTextFg->c;
|
||||||
|
color.setAlphaF(color.alphaF() * kTextLinesAlpha);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(color);
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
|
||||||
|
const auto available = outerWidth - _margins.left() - _margins.right();
|
||||||
|
const auto lineHeight = st::tagPreviewLineHeight;
|
||||||
|
const auto radius = lineHeight / 2.0;
|
||||||
|
const auto fractions = { 1.0, 0.85, 0.65, 0.4 };
|
||||||
|
auto y = double(_margins.top());
|
||||||
|
for (const auto fraction : fractions) {
|
||||||
|
const auto w = available * fraction;
|
||||||
|
p.drawRoundedRect(
|
||||||
|
QRectF(_margins.left(), y, w, lineHeight),
|
||||||
|
radius,
|
||||||
|
radius);
|
||||||
|
y += lineHeight + st::tagPreviewLineSpacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TagPreviewDelegate final : public DefaultElementDelegate {
|
||||||
|
public:
|
||||||
|
TagPreviewDelegate(
|
||||||
|
not_null<QWidget*> parent,
|
||||||
|
not_null<Ui::ChatStyle*> st,
|
||||||
|
Fn<void()> update);
|
||||||
|
|
||||||
|
void setTagText(const QString &text);
|
||||||
|
[[nodiscard]] const QString &tagText() const;
|
||||||
|
|
||||||
|
bool elementAnimationsPaused() override;
|
||||||
|
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
|
||||||
|
Context elementContext() override;
|
||||||
|
QString elementAuthorRank(not_null<const Element*> view) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const not_null<QWidget*> _parent;
|
||||||
|
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
|
||||||
|
QString _tagText;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TagPreviewDelegate::TagPreviewDelegate(
|
||||||
|
not_null<QWidget*> parent,
|
||||||
|
not_null<Ui::ChatStyle*> st,
|
||||||
|
Fn<void()> update)
|
||||||
|
: _parent(parent)
|
||||||
|
, _pathGradient(MakePathShiftGradient(st, std::move(update))) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagPreviewDelegate::setTagText(const QString &text) {
|
||||||
|
_tagText = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &TagPreviewDelegate::tagText() const {
|
||||||
|
return _tagText;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagPreviewDelegate::elementAnimationsPaused() {
|
||||||
|
return _parent->window()->isActiveWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto TagPreviewDelegate::elementPathShiftGradient()
|
||||||
|
-> not_null<Ui::PathShiftGradient*> {
|
||||||
|
return _pathGradient.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Context TagPreviewDelegate::elementContext() {
|
||||||
|
return Context::AdminLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TagPreviewDelegate::elementAuthorRank(
|
||||||
|
not_null<const Element*> view) {
|
||||||
|
return _tagText;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
HistoryView::BadgeRole LookupBadgeRole(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
not_null<UserData*> user) {
|
||||||
|
if (const auto channel = peer->asMegagroup()) {
|
||||||
|
const auto info = channel->mgInfo.get();
|
||||||
|
if (info && info->creator == user) {
|
||||||
|
return HistoryView::BadgeRole::Creator;
|
||||||
|
}
|
||||||
|
const auto userId = peerToUser(user->id);
|
||||||
|
if (info && info->admins.contains(userId)) {
|
||||||
|
return HistoryView::BadgeRole::Admin;
|
||||||
|
}
|
||||||
|
} else if (const auto chat = peer->asChat()) {
|
||||||
|
if (peerToUser(user->id) == chat->creator) {
|
||||||
|
return HistoryView::BadgeRole::Creator;
|
||||||
|
} else if (chat->admins.contains(user)) {
|
||||||
|
return HistoryView::BadgeRole::Admin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HistoryView::BadgeRole::User;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EditTagControl::PreviewWidget final : public Ui::RpWidget {
|
||||||
|
public:
|
||||||
|
PreviewWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
not_null<UserData*> user,
|
||||||
|
const QString &initialText,
|
||||||
|
HistoryView::BadgeRole role);
|
||||||
|
~PreviewWidget();
|
||||||
|
|
||||||
|
void setTagText(const QString &text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void createItem();
|
||||||
|
void applyBadge(const QString &text);
|
||||||
|
|
||||||
|
const not_null<History*> _history;
|
||||||
|
const not_null<UserData*> _user;
|
||||||
|
const HistoryView::BadgeRole _role;
|
||||||
|
const std::unique_ptr<Ui::ChatTheme> _theme;
|
||||||
|
const std::unique_ptr<Ui::ChatStyle> _style;
|
||||||
|
const std::unique_ptr<TagPreviewDelegate> _delegate;
|
||||||
|
AdminLog::OwnedItem _item;
|
||||||
|
QPoint _position;
|
||||||
|
Ui::PeerUserpicView _userpic;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
EditTagControl::PreviewWidget::PreviewWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
not_null<UserData*> user,
|
||||||
|
const QString &initialText,
|
||||||
|
HistoryView::BadgeRole role)
|
||||||
|
: RpWidget(parent)
|
||||||
|
, _history(session->data().history(PeerData::kServiceNotificationsId))
|
||||||
|
, _user(user)
|
||||||
|
, _role(role)
|
||||||
|
, _theme(Window::Theme::DefaultChatThemeOn(lifetime()))
|
||||||
|
, _style(std::make_unique<Ui::ChatStyle>(
|
||||||
|
session->colorIndicesValue()))
|
||||||
|
, _delegate(std::make_unique<TagPreviewDelegate>(
|
||||||
|
this,
|
||||||
|
_style.get(),
|
||||||
|
[=] { update(); }))
|
||||||
|
, _position(0, st::msgMargin.bottom()) {
|
||||||
|
_style->apply(_theme.get());
|
||||||
|
_delegate->setTagText(initialText);
|
||||||
|
|
||||||
|
_history->owner().viewRepaintRequest(
|
||||||
|
) | rpl::on_next([=](Data::RequestViewRepaint data) {
|
||||||
|
if (data.view == _item.get()) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
createItem();
|
||||||
|
|
||||||
|
widthValue(
|
||||||
|
) | rpl::filter([=](int w) {
|
||||||
|
return w >= st::msgMinWidth;
|
||||||
|
}) | rpl::on_next([=](int w) {
|
||||||
|
const auto h = _position.y()
|
||||||
|
+ _item->resizeGetHeight(w)
|
||||||
|
+ _position.y();
|
||||||
|
resize(w, h);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_history->owner().itemResizeRequest(
|
||||||
|
) | rpl::on_next([=](not_null<const HistoryItem*> item) {
|
||||||
|
if (_item && item == _item->data() && width() >= st::msgMinWidth) {
|
||||||
|
const auto h = _position.y()
|
||||||
|
+ _item->resizeGetHeight(width())
|
||||||
|
+ _position.y();
|
||||||
|
resize(width(), h);
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
EditTagControl::PreviewWidget::~PreviewWidget() {
|
||||||
|
_item = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditTagControl::PreviewWidget::createItem() {
|
||||||
|
const auto item = _history->addNewLocalMessage({
|
||||||
|
.id = _history->nextNonHistoryEntryId(),
|
||||||
|
.flags = (MessageFlag::FakeHistoryItem
|
||||||
|
| MessageFlag::HasFromId),
|
||||||
|
.from = _user->id,
|
||||||
|
.date = base::unixtime::now(),
|
||||||
|
}, TextWithEntities(), MTP_messageMediaEmpty());
|
||||||
|
|
||||||
|
auto owned = AdminLog::OwnedItem(_delegate.get(), item);
|
||||||
|
owned->overrideMedia(std::make_unique<HistoryView::MediaGeneric>(
|
||||||
|
owned.get(),
|
||||||
|
[](not_null<HistoryView::MediaGeneric*>,
|
||||||
|
Fn<void(std::unique_ptr<HistoryView::MediaGenericPart>)> push) {
|
||||||
|
push(std::make_unique<TextLinesPart>(st::msgPadding));
|
||||||
|
}));
|
||||||
|
_item = std::move(owned);
|
||||||
|
applyBadge(_delegate->tagText());
|
||||||
|
if (width() >= st::msgMinWidth) {
|
||||||
|
const auto h = _position.y()
|
||||||
|
+ _item->resizeGetHeight(width())
|
||||||
|
+ _position.y();
|
||||||
|
resize(width(), h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditTagControl::PreviewWidget::applyBadge(const QString &text) {
|
||||||
|
if (_item) {
|
||||||
|
_item->overrideRightBadge(text, _role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditTagControl::PreviewWidget::setTagText(const QString &text) {
|
||||||
|
_delegate->setTagText(text);
|
||||||
|
applyBadge(text);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditTagControl::PreviewWidget::paintEvent(QPaintEvent *e) {
|
||||||
|
auto p = Painter(this);
|
||||||
|
|
||||||
|
const auto clip = e->rect();
|
||||||
|
if (!clip.isEmpty()) {
|
||||||
|
p.setClipRect(clip);
|
||||||
|
Window::SectionWidget::PaintBackground(
|
||||||
|
p,
|
||||||
|
_theme.get(),
|
||||||
|
QSize(width(), window()->height()),
|
||||||
|
clip);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto context = _theme->preparePaintContext(
|
||||||
|
_style.get(),
|
||||||
|
rect(),
|
||||||
|
rect(),
|
||||||
|
e->rect(),
|
||||||
|
!window()->isActiveWindow());
|
||||||
|
p.translate(_position);
|
||||||
|
_item->draw(p, context);
|
||||||
|
|
||||||
|
if (_item->displayFromPhoto()) {
|
||||||
|
auto userpicBottom = height()
|
||||||
|
- _item->marginBottom()
|
||||||
|
- _item->marginTop();
|
||||||
|
const auto userpicTop = userpicBottom - st::msgPhotoSize;
|
||||||
|
_user->paintUserpicLeft(
|
||||||
|
p,
|
||||||
|
_userpic,
|
||||||
|
st::historyPhotoLeft,
|
||||||
|
userpicTop,
|
||||||
|
width(),
|
||||||
|
st::msgPhotoSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditTagControl::EditTagControl(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
not_null<UserData*> user,
|
||||||
|
const QString ¤tRank,
|
||||||
|
HistoryView::BadgeRole role)
|
||||||
|
: RpWidget(parent)
|
||||||
|
, _preview(Ui::CreateChild<PreviewWidget>(
|
||||||
|
this,
|
||||||
|
session,
|
||||||
|
user,
|
||||||
|
TextUtilities::RemoveEmoji(currentRank),
|
||||||
|
role))
|
||||||
|
, _field(Ui::CreateChild<Ui::InputField>(
|
||||||
|
this,
|
||||||
|
st::customBadgeField,
|
||||||
|
tr::lng_rights_edit_admin_rank_name(),
|
||||||
|
TextUtilities::RemoveEmoji(currentRank))) {
|
||||||
|
_field->setMaxLength(kRankLimit);
|
||||||
|
_field->setInstantReplaces(Ui::InstantReplaces::TextOnly());
|
||||||
|
|
||||||
|
_field->changes(
|
||||||
|
) | rpl::on_next([=] {
|
||||||
|
const auto text = _field->getLastText();
|
||||||
|
const auto removed = TextUtilities::RemoveEmoji(text);
|
||||||
|
if (removed != text) {
|
||||||
|
_field->setText(removed);
|
||||||
|
}
|
||||||
|
_preview->setTagText(_field->getLastText());
|
||||||
|
}, _field->lifetime());
|
||||||
|
|
||||||
|
widthValue(
|
||||||
|
) | rpl::on_next([=](int w) {
|
||||||
|
_preview->resizeToWidth(w);
|
||||||
|
const auto inputMargins = st::boxRowPadding;
|
||||||
|
_field->resizeToWidth(w - inputMargins.left() - inputMargins.right());
|
||||||
|
_field->moveToLeft(
|
||||||
|
inputMargins.left(),
|
||||||
|
_preview->height() + st::tagPreviewInputSkip);
|
||||||
|
resize(w, _field->y() + _field->height());
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_preview->heightValue(
|
||||||
|
) | rpl::skip(1) | rpl::on_next([=] {
|
||||||
|
_field->moveToLeft(
|
||||||
|
st::boxRowPadding.left(),
|
||||||
|
_preview->height() + st::tagPreviewInputSkip);
|
||||||
|
resize(width(), _field->y() + _field->height());
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
EditTagControl::~EditTagControl() = default;
|
||||||
|
|
||||||
|
QString EditTagControl::currentRank() const {
|
||||||
|
return TextUtilities::RemoveEmoji(
|
||||||
|
TextUtilities::SingleLine(_field->getLastText().trimmed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
not_null<Ui::InputField*> EditTagControl::field() const {
|
||||||
|
return _field;
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class InputField;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Main {
|
||||||
|
class Session;
|
||||||
|
} // namespace Main
|
||||||
|
|
||||||
|
class PeerData;
|
||||||
|
class UserData;
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
enum class BadgeRole : uchar;
|
||||||
|
} // namespace HistoryView
|
||||||
|
|
||||||
|
[[nodiscard]] HistoryView::BadgeRole LookupBadgeRole(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
not_null<UserData*> user);
|
||||||
|
|
||||||
|
class EditTagControl final : public Ui::RpWidget {
|
||||||
|
public:
|
||||||
|
EditTagControl(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
not_null<UserData*> user,
|
||||||
|
const QString ¤tRank,
|
||||||
|
HistoryView::BadgeRole role);
|
||||||
|
~EditTagControl();
|
||||||
|
|
||||||
|
[[nodiscard]] QString currentRank() const;
|
||||||
|
[[nodiscard]] not_null<Ui::InputField*> field() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PreviewWidget;
|
||||||
|
|
||||||
|
not_null<PreviewWidget*> _preview;
|
||||||
|
not_null<Ui::InputField*> _field;
|
||||||
|
|
||||||
|
};
|
||||||
@@ -1579,6 +1579,7 @@ void InnerWidget::suggestRestrictParticipant(
|
|||||||
user,
|
user,
|
||||||
hasAdminRights,
|
hasAdminRights,
|
||||||
currentRights,
|
currentRights,
|
||||||
|
QString(),
|
||||||
by,
|
by,
|
||||||
since);
|
since);
|
||||||
box->setSaveCallback([=](
|
box->setSaveCallback([=](
|
||||||
|
|||||||
@@ -1422,6 +1422,40 @@ void Element::overrideMedia(std::unique_ptr<Media> media) {
|
|||||||
_flags |= Flag::MediaOverriden;
|
_flags |= Flag::MediaOverriden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Element::overrideRightBadge(const QString &text, BadgeRole role) {
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
if (Has<RightBadge>()) {
|
||||||
|
Get<RightBadge>()->overridden = false;
|
||||||
|
RemoveComponents(RightBadge::Bit());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Has<RightBadge>()) {
|
||||||
|
AddComponents(RightBadge::Bit());
|
||||||
|
}
|
||||||
|
const auto badge = Get<RightBadge>();
|
||||||
|
badge->overridden = true;
|
||||||
|
badge->role = role;
|
||||||
|
badge->tag.setMarkedText(
|
||||||
|
st::defaultTextStyle,
|
||||||
|
{ text },
|
||||||
|
Ui::NameTextOptions());
|
||||||
|
badge->boosts.clear();
|
||||||
|
if (role == BadgeRole::User) {
|
||||||
|
badge->width = badge->tag.maxWidth();
|
||||||
|
} else {
|
||||||
|
const auto &padding = st::msgTagBadgePadding;
|
||||||
|
const auto tagTextWidth = badge->tag.maxWidth();
|
||||||
|
const auto contentWidth = padding.left()
|
||||||
|
+ tagTextWidth
|
||||||
|
+ padding.right();
|
||||||
|
const auto pillHeight = padding.top()
|
||||||
|
+ st::msgFont->height
|
||||||
|
+ padding.bottom();
|
||||||
|
badge->width = std::max(contentWidth, pillHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
not_null<PurchasedTag*> Element::enforcePurchasedTag() {
|
not_null<PurchasedTag*> Element::enforcePurchasedTag() {
|
||||||
if (const auto purchased = Get<PurchasedTag>()) {
|
if (const auto purchased = Get<PurchasedTag>()) {
|
||||||
return purchased;
|
return purchased;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class InlineList;
|
|||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
using PaintContext = Ui::ChatPaintContext;
|
using PaintContext = Ui::ChatPaintContext;
|
||||||
|
enum class BadgeRole : uchar;
|
||||||
enum class PointState : char;
|
enum class PointState : char;
|
||||||
enum class InfoDisplayType : char;
|
enum class InfoDisplayType : char;
|
||||||
struct StateRequest;
|
struct StateRequest;
|
||||||
@@ -661,6 +662,7 @@ public:
|
|||||||
-> std::unique_ptr<Ui::ReactionFlyAnimation>;
|
-> std::unique_ptr<Ui::ReactionFlyAnimation>;
|
||||||
|
|
||||||
void overrideMedia(std::unique_ptr<Media> media);
|
void overrideMedia(std::unique_ptr<Media> media);
|
||||||
|
void overrideRightBadge(const QString &text, BadgeRole role);
|
||||||
|
|
||||||
[[nodiscard]] not_null<PurchasedTag*> enforcePurchasedTag();
|
[[nodiscard]] not_null<PurchasedTag*> enforcePurchasedTag();
|
||||||
|
|
||||||
|
|||||||
@@ -257,6 +257,9 @@ void Message::initPaidInformation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Message::refreshRightBadge() {
|
void Message::refreshRightBadge() {
|
||||||
|
if (const auto badge = Get<RightBadge>(); badge && badge->overridden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto item = data();
|
const auto item = data();
|
||||||
const auto [text, role] = [&]() -> std::pair<QString, BadgeRole> {
|
const auto [text, role] = [&]() -> std::pair<QString, BadgeRole> {
|
||||||
if (item->isDiscussionPost()) {
|
if (item->isDiscussionPost()) {
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ struct RightBadge : RuntimeComponent<RightBadge, Element> {
|
|||||||
Ui::Text::String boosts;
|
Ui::Text::String boosts;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
BadgeRole role = BadgeRole::User;
|
BadgeRole role = BadgeRole::User;
|
||||||
|
bool overridden = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BottomRippleMask {
|
struct BottomRippleMask {
|
||||||
|
|||||||
@@ -1459,4 +1459,4 @@ earnTonIconMargin: margins(0px, 2px, 0px, 0px);
|
|||||||
infoMusicButtonRipple: universalRippleAnimation;
|
infoMusicButtonRipple: universalRippleAnimation;
|
||||||
infoMusicButtonPadding: margins(16px, 6px, 13px, 6px);
|
infoMusicButtonPadding: margins(16px, 6px, 13px, 6px);
|
||||||
|
|
||||||
memberTagPillPadding: margins(5px, 1px, 5px, 1px);
|
memberTagPillPadding: margins(5px, -1px, 5px, 0px);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ msgMinWidth: 160px;
|
|||||||
msgPhotoSize: 33px;
|
msgPhotoSize: 33px;
|
||||||
msgPhotoSkip: 40px;
|
msgPhotoSkip: 40px;
|
||||||
msgPadding: margins(11px, 8px, 11px, 8px);
|
msgPadding: margins(11px, 8px, 11px, 8px);
|
||||||
msgTagBadgePadding: margins(5px, 0px, 5px, 0px);
|
msgTagBadgePadding: margins(5px, -1px, 5px, 0px);
|
||||||
msgTagBadgeBoostSkip: 2px;
|
msgTagBadgeBoostSkip: 2px;
|
||||||
msgMargin: margins(16px, 6px, 56px, 2px);
|
msgMargin: margins(16px, 6px, 56px, 2px);
|
||||||
msgMarginTopAttached: 0px;
|
msgMarginTopAttached: 0px;
|
||||||
|
|||||||
Reference in New Issue
Block a user