diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 37509fd5d..de3ccf75b 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1184,6 +1184,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_group_invite_about_permanent_channel" = "Anyone who has Telegram installed will be able to join your channel by following this link."; "lng_group_invite_manage" = "Manage Invite Links"; "lng_group_invite_manage_about" = "You can create additional invite links that have limited time or number of usages."; +"lng_group_invite_title" = "Invite links"; "lng_group_invite_add" = "Create a New Link"; "lng_group_invite_expires_at" = "This link expires {when}."; "lng_group_invite_created_by" = "Link created by"; diff --git a/Telegram/SourceFiles/api/api_invite_links.cpp b/Telegram/SourceFiles/api/api_invite_links.cpp index 5651afa3d..c01f54d55 100644 --- a/Telegram/SourceFiles/api/api_invite_links.cpp +++ b/Telegram/SourceFiles/api/api_invite_links.cpp @@ -218,6 +218,12 @@ void InviteLinks::revoke( performEdit(peer, link, std::move(done), true); } +void InviteLinks::revokePermanent( + not_null peer, + Fn done) { + performCreate(peer, std::move(done), true); +} + void InviteLinks::requestLinks(not_null peer) { if (_firstSliceRequests.contains(peer)) { return; @@ -411,6 +417,7 @@ auto InviteLinks::parse( .link = qs(data.vlink()), .admin = peer->session().data().user(data.vadmin_id().v), .date = data.vdate().v, + .startDate = data.vstart_date().value_or_empty(), .expireDate = data.vexpire_date().value_or_empty(), .usageLimit = data.vusage_limit().value_or_empty(), .usage = data.vusage().value_or_empty(), diff --git a/Telegram/SourceFiles/api/api_invite_links.h b/Telegram/SourceFiles/api/api_invite_links.h index 8d78a8f18..096038c06 100644 --- a/Telegram/SourceFiles/api/api_invite_links.h +++ b/Telegram/SourceFiles/api/api_invite_links.h @@ -14,7 +14,8 @@ namespace Api { struct InviteLink { QString link; not_null admin; - TimeId date; + TimeId date = 0; + TimeId startDate = 0; TimeId expireDate = 0; int usageLimit = 0; int usage = 0; @@ -60,6 +61,9 @@ public: not_null peer, const QString &link, Fn done = nullptr); + void revokePermanent( + not_null peer, + Fn done = nullptr); void setPermanent( not_null peer, diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp index fd8c9cc6d..e0db55baa 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp @@ -194,39 +194,6 @@ PaintRoundImageCallback ExceptionRow::generatePaintUserpicCallback() { }; } -void TypeDelegate::peerListSetTitle(rpl::producer title) { -} - -void TypeDelegate::peerListSetAdditionalTitle(rpl::producer title) { -} - -bool TypeDelegate::peerListIsRowChecked(not_null row) { - return false; -} - -int TypeDelegate::peerListSelectedRowsCount() { - return 0; -} - -void TypeDelegate::peerListScrollToTop() { -} - -void TypeDelegate::peerListAddSelectedPeerInBunch(not_null peer) { - Unexpected("Item selection in Info::Profile::Members."); -} - -void TypeDelegate::peerListAddSelectedRowInBunch(not_null row) { - Unexpected("Item selection in Info::Profile::Members."); -} - -void TypeDelegate::peerListFinishSelectedRowsBunch() { -} - -void TypeDelegate::peerListSetDescription( - object_ptr description) { - description.destroy(); -} - TypeController::TypeController( not_null session, Flags options, @@ -412,7 +379,9 @@ object_ptr EditFilterChatsListController::prepareTypesList() { container->add(object_ptr( container, st::membersMarginTop)); - const auto delegate = container->lifetime().make_state(); + const auto delegate = container->lifetime().make_state< + PeerListContentDelegateSimple + >(); const auto controller = container->lifetime().make_state( &session(), _options, diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h index eed2af665..b9ce4f203 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.h +++ b/Telegram/SourceFiles/boxes/peer_list_box.h @@ -302,7 +302,7 @@ public: virtual void peerListShowRowMenu( not_null row, - Fn)> destroyed) = 0; + Fn)> destroyed = nullptr) = 0; virtual int peerListSelectedRowsCount() = 0; virtual std::unique_ptr peerListSaveState() const = 0; virtual void peerListRestoreState( @@ -837,7 +837,7 @@ public: } void peerListShowRowMenu( not_null row, - Fn)> destroyed) override { + Fn)> destroyed = nullptr) override { _content->showRowMenu(row, std::move(destroyed)); } @@ -851,6 +851,38 @@ private: }; +class PeerListContentDelegateSimple : public PeerListContentDelegate { +public: + void peerListSetTitle(rpl::producer title) override { + } + void peerListSetAdditionalTitle(rpl::producer title) override { + } + bool peerListIsRowChecked(not_null row) override { + return false; + } + int peerListSelectedRowsCount() override { + return 0; + } + void peerListScrollToTop() override { + } + void peerListAddSelectedPeerInBunch( + not_null peer) override { + Unexpected("...DelegateSimple::peerListAddSelectedPeerInBunch"); + } + void peerListAddSelectedRowInBunch(not_null row) override { + Unexpected("...DelegateSimple::peerListAddSelectedRowInBunch"); + } + void peerListFinishSelectedRowsBunch() override { + Unexpected("...DelegateSimple::peerListFinishSelectedRowsBunch"); + } + void peerListSetDescription( + object_ptr description) override { + description.destroy(); + } + +}; + + class PeerListBox : public Ui::BoxContent , public PeerListContentDelegate { diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index 7c3c9f0c1..9ebdc480c 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/edit_peer_type_box.h" #include "boxes/peers/edit_peer_history_visibility_box.h" #include "boxes/peers/edit_peer_permissions_box.h" +#include "boxes/peers/edit_peer_invite_links.h" #include "boxes/peers/edit_linked_chat_box.h" #include "boxes/stickers_box.h" #include "chat_helpers/emoji_suggestions_widget.h" @@ -1003,7 +1004,7 @@ void Controller::fillManageSection() { }); }) | rpl::flatten_latest( ) | ToPositiveNumberString(), - [=] { }, + [=] { Ui::show(Box(ManageInviteLinksBox, _peer)); }, st::infoIconInviteLinks); } if (canViewAdmins) { diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp index eb5b5569b..28815f842 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp @@ -15,8 +15,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "api/api_invite_links.h" #include "ui/wrap/vertical_layout.h" +#include "ui/wrap/slide_wrap.h" #include "ui/wrap/padding_wrap.h" #include "ui/abstract_button.h" +#include "ui/widgets/buttons.h" #include "ui/widgets/popup_menu.h" #include "ui/controls/invite_link_label.h" #include "ui/controls/invite_link_buttons.h" @@ -29,17 +31,152 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/confirm_box.h" #include "boxes/peer_list_box.h" #include "boxes/peer_list_controllers.h" +#include "settings/settings_common.h" // AddDivider. #include "apiwrap.h" #include "mainwindow.h" #include "boxes/share_box.h" +#include "base/weak_ptr.h" +#include "base/unixtime.h" #include "window/window_session_controller.h" #include "api/api_common.h" #include "styles/style_info.h" +#include + #include namespace { +constexpr auto kPreloadPages = 2; +constexpr auto kExpireSoonNominator = 3; +constexpr auto kExpireSoonDenominator = 4; + +enum class Color { + Permanent, + Expiring, + ExpireSoon, + Expired, + Revoked, + + Count, +}; + +using InviteLinkData = Api::InviteLink; +using InviteLinksSlice = Api::PeerInviteLinks; + +struct InviteLinkAction { + enum class Type { + Copy, + Share, + Edit, + Revoke, + Delete, + }; + QString link; + Type type = Type::Copy; +}; + +class Row; + +class RowDelegate { +public: + virtual void rowUpdateRow(not_null row) = 0; + virtual void rowPaintIcon( + QPainter &p, + int x, + int y, + int size, + float64 progress, + Color color) = 0; +}; + +class Row final : public PeerListRow { +public: + Row( + not_null delegate, + const InviteLinkData &data, + TimeId now); + + void update(const InviteLinkData &data); + + [[nodiscard]] InviteLinkData data() const; + + QString generateName() override; + QString generateShortName() override; + PaintRoundImageCallback generatePaintUserpicCallback() override; + + QSize actionSize() const override; + QMargins actionMargins() const override; + void paintAction( + Painter &p, + int x, + int y, + int outerWidth, + bool selected, + bool actionSelected) override; + +private: + const not_null _delegate; + InviteLinkData _data; + QString _status; + float64 _progressTillExpire = 0.; + Color _color = Color::Permanent; + +}; + +[[nodiscard]] uint64 ComputeRowId(const QString &link) { + return XXH64(link.data(), link.size() * sizeof(ushort), 0); +} + +[[nodiscard]] uint64 ComputeRowId(const InviteLinkData &data) { + return ComputeRowId(data.link); +} + +[[nodiscard]] float64 ComputeProgress( + const InviteLinkData &link, + TimeId now) { + const auto startDate = link.startDate ? link.startDate : link.date; + if (link.expireDate <= startDate && link.usageLimit <= 0) { + return -1; + } + const auto expireProgress = (link.expireDate <= startDate + || now <= startDate) + ? 0. + : (link.expireDate <= now) + ? 1. + : (now - startDate) / float64(link.expireDate - startDate); + const auto usageProgress = (link.usageLimit <= 0 || link.usage <= 0) + ? 0. + : (link.usageLimit <= link.usage) + ? 1. + : link.usage / float64(link.usageLimit); + return std::max(expireProgress, usageProgress); +} + +[[nodiscard]] Color ComputeColor( + const InviteLinkData &link, + float64 progress) { + const auto startDate = link.startDate ? link.startDate : link.date; + return link.revoked + ? Color::Revoked + : (progress >= 1.) + ? Color::Expired + : (progress >= 3 / 4.) + ? Color::ExpireSoon + : (progress >= 0.) + ? Color::Expiring + : Color::Permanent; +} + +[[nodiscard]] QString ComputeStatus(const InviteLinkData &link) { + return "nothing"; +} + +void CopyLink(const QString &link) { + QGuiApplication::clipboard()->setText(link); + Ui::Toast::Show(tr::lng_group_invite_copied(tr::now)); +} + void ShareLinkBox(not_null peer, const QString &link) { const auto session = &peer->session(); const auto sending = std::make_shared(); @@ -118,6 +255,323 @@ void ShareLinkBox(not_null peer, const QString &link) { std::move(filterCallback))); } +not_null AddCreateLinkButton( + not_null container) { + const auto result = container->add( + object_ptr( + container, + tr::lng_group_invite_add(), + st::inviteLinkCreate), + style::margins(0, st::inviteLinkCreateSkip, 0, 0)); + const auto icon = Ui::CreateChild(result); + icon->setAttribute(Qt::WA_TransparentForMouseEvents); + const auto size = st::inviteLinkCreateIconSize; + icon->resize(size, size); + result->heightValue( + ) | rpl::start_with_next([=](int height) { + const auto &st = st::inviteLinkList.item; + icon->move( + st.photoPosition.x() + (st.photoSize - size) / 2, + (height - size) / 2); + }, icon->lifetime()); + icon->paintRequest( + ) | rpl::start_with_next([=] { + auto p = QPainter(icon); + p.setPen(Qt::NoPen); + p.setBrush(st::windowBgActive); + const auto rect = icon->rect(); + auto hq = PainterHighQualityEnabler(p); + p.drawEllipse(rect); + st::inviteLinkCreateIcon.paintInCenter(p, rect); + }, icon->lifetime()); + return result; +} + +void EditLinkBox( + not_null box, + not_null peer, + const InviteLinkData &data) { + box->setTitle(data.link.isEmpty() + ? tr::lng_group_invite_new_title() + : tr::lng_group_invite_edit_title()); +} + +void CreateLinkBox( + not_null box, + not_null peer) { + EditLinkBox( + box, + peer, + InviteLinkData{ .admin = peer->session().user() }); +} + +Row::Row( + not_null delegate, + const InviteLinkData &data, + TimeId now) +: PeerListRow(ComputeRowId(data)) +, _delegate(delegate) +, _data(data) +, _progressTillExpire(ComputeProgress(data, now)) +, _color(ComputeColor(data, _progressTillExpire)) { + setCustomStatus(ComputeStatus(data)); +} + +void Row::update(const InviteLinkData &data) { + _data = data; + _progressTillExpire = ComputeProgress(data, base::unixtime::now()); + _color = ComputeColor(data, _progressTillExpire); + setCustomStatus(ComputeStatus(data)); + _delegate->rowUpdateRow(this); +} + +InviteLinkData Row::data() const { + return _data; +} + +QString Row::generateName() { + auto result = _data.link; + return result.replace(qstr("https://"), QString()); +} + +QString Row::generateShortName() { + return generateName(); +} + +PaintRoundImageCallback Row::generatePaintUserpicCallback() { + return [=]( + Painter &p, + int x, + int y, + int outerWidth, + int size) { + _delegate->rowPaintIcon(p, x, y, size, _progressTillExpire, _color); + }; +} + +QSize Row::actionSize() const { + return QSize( + st::inviteLinkThreeDotsIcon.width(), + st::inviteLinkThreeDotsIcon.height()); +} + +QMargins Row::actionMargins() const { + return QMargins( + 0, + (st::inviteLinkList.item.height - actionSize().height()) / 2, + st::inviteLinkThreeDotsSkip, + 0); +} + +void Row::paintAction( + Painter &p, + int x, + int y, + int outerWidth, + bool selected, + bool actionSelected) { + (actionSelected + ? st::inviteLinkThreeDotsIconOver + : st::inviteLinkThreeDotsIcon).paint(p, x, y, outerWidth); +} + +class Controller final + : public PeerListController + , public RowDelegate + , public base::has_weak_ptr { +public: + explicit Controller(not_null peer); + + void prepare() override; + void rowClicked(not_null row) override; + void rowActionClicked(not_null row) override; + base::unique_qptr rowContextMenu( + QWidget *parent, + not_null row) override; + Main::Session &session() const override; + + void rowUpdateRow(not_null row) override; + void rowPaintIcon( + QPainter &p, + int x, + int y, + int size, + float64 progress, + Color color) override; + +private: + void appendRow(const InviteLinkData &data, TimeId now); + [[nodiscard]] base::unique_qptr createRowContextMenu( + QWidget *parent, + not_null row); + + not_null _peer; + base::unique_qptr _menu; + + std::array _icons; + rpl::lifetime _lifetime; + +}; + +Controller::Controller(not_null peer) +: _peer(peer) { + style::PaletteChanged( + ) | rpl::start_with_next([=] { + for (auto &image : _icons) { + image = QImage(); + } + }, _lifetime); +} + +void Controller::prepare() { + const auto now = base::unixtime::now(); + const auto &links = _peer->session().api().inviteLinks().links(_peer); + for (const auto &link : links.links) { + if (!link.permanent || link.revoked) { + appendRow(link, now); + } + } + delegate()->peerListRefreshRows(); +} + +void Controller::rowClicked(not_null row) { + // #TODO links show +} + +void Controller::rowActionClicked(not_null row) { + delegate()->peerListShowRowMenu(row, nullptr); +} + +base::unique_qptr Controller::rowContextMenu( + QWidget *parent, + not_null row) { + auto result = createRowContextMenu(parent, row); + + if (result) { + // First clear _menu value, so that we don't check row positions yet. + base::take(_menu); + + // Here unique_qptr is used like a shared pointer, where + // not the last destroyed pointer destroys the object, but the first. + _menu = base::unique_qptr(result.get()); + } + + return result; +} + +base::unique_qptr Controller::createRowContextMenu( + QWidget *parent, + not_null row) { + const auto real = static_cast(row.get()); + const auto data = real->data(); + const auto link = data.link; + auto result = base::make_unique_q(parent); + if (data.revoked) { + //result->addAction(tr::lng_group_invite_context_delete(tr::now), [=] { + // // #TODO links delete + //}); + } else { + result->addAction(tr::lng_group_invite_context_copy(tr::now), [=] { + CopyLink(link); + }); + result->addAction(tr::lng_group_invite_context_share(tr::now), [=] { + ShareLinkBox(_peer, link); + }); + result->addAction(tr::lng_group_invite_context_edit(tr::now), [=] { + Ui::show( + Box(EditLinkBox, _peer, data), + Ui::LayerOption::KeepOther); + }); + result->addAction(tr::lng_group_invite_context_revoke(tr::now), [=] { + const auto box = std::make_shared>(); + const auto revoke = crl::guard(this, [=] { + const auto done = crl::guard(this, [=](InviteLinkData data) { + // #TODO links add to revoked, remove from list + if (*box) { + (*box)->closeBox(); + } + }); + _peer->session().api().inviteLinks().revoke( + _peer, + link, + done); + }); + *box = Ui::show( + Box( + tr::lng_group_invite_revoke_about(tr::now), + revoke), + Ui::LayerOption::KeepOther); + }); + } + return result; +} + +Main::Session &Controller::session() const { + return _peer->session(); +} + +void Controller::appendRow(const InviteLinkData &data, TimeId now) { + delegate()->peerListAppendRow(std::make_unique(this, data, now)); +} + +void Controller::rowUpdateRow(not_null row) { + delegate()->peerListUpdateRow(row); +} + +void Controller::rowPaintIcon( + QPainter &p, + int x, + int y, + int size, + float64 progress, + Color color) { + const auto skip = st::inviteLinkIconSkip; + const auto inner = size - 2 * skip; + const auto bg = [&] { + switch (color) { + case Color::Permanent: return &st::msgFile1Bg; + case Color::Expiring: return &st::msgFile2Bg; + case Color::ExpireSoon: return &st::msgFile4Bg; + case Color::Expired: return &st::msgFile3Bg; + case Color::Revoked: return &st::windowSubTextFg; + } + Unexpected("Color in Controller::rowPaintIcon."); + }(); + auto &icon = _icons[int(color)]; + if (icon.isNull()) { + icon = QImage( + QSize(inner, inner) * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied); + icon.fill(Qt::transparent); + icon.setDevicePixelRatio(style::DevicePixelRatio()); + + auto p = QPainter(&icon); + p.setPen(Qt::NoPen); + p.setBrush(*bg); + auto hq = PainterHighQualityEnabler(p); + p.drawEllipse(0, 0, inner, inner); + st::inviteLinkIcon.paintInCenter(p, { 0, 0, inner, inner }); + } + p.drawImage(x + skip, y + skip, icon); + if (progress >= 0. && progress < 1.) { + const auto kFullArcLength = 360 * 16; + const auto stroke = st::inviteLinkIconStroke; + auto hq = PainterHighQualityEnabler(p); + auto pen = QPen((*bg)->c); + pen.setWidth(stroke); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + + const auto margins = 1.5 * stroke; + p.drawArc(QRectF(x + skip, y + skip, inner, inner).marginsAdded({ + margins, + margins, + margins, + margins, + }), 0, kFullArcLength * progress); + } +} + } // namespace void AddPermanentLinkBlock( @@ -143,8 +597,7 @@ void AddPermanentLinkBlock( const auto weak = Ui::MakeWeak(container); const auto copyLink = crl::guard(weak, [=] { if (const auto link = computePermanentLink()) { - QGuiApplication::clipboard()->setText(link->link); - Ui::Toast::Show(tr::lng_group_invite_copied(tr::now)); + CopyLink(link->link); } }); const auto shareLink = crl::guard(weak, [=] { @@ -155,17 +608,12 @@ void AddPermanentLinkBlock( const auto revokeLink = crl::guard(weak, [=] { const auto box = std::make_shared>(); const auto done = crl::guard(weak, [=] { - if (const auto link = computePermanentLink()) { - const auto close = [=](auto&&) { - if (*box) { - (*box)->closeBox(); - } - }; - peer->session().api().inviteLinks().revoke( - peer, - link->link, - close); - } + const auto close = [=](auto&&) { + if (*box) { + (*box)->closeBox(); + } + }; + peer->session().api().inviteLinks().revokePermanent(peer, close); }); *box = Ui::show( Box(tr::lng_group_invite_about_new(tr::now), done), @@ -286,4 +734,40 @@ void AddPermanentLinkBlock( st::inviteLinkJoinedRowPadding )->setClickedCallback([=] { }); + + container->add(object_ptr>( + container, + object_ptr( + container, + st::inviteLinkJoinedRowPadding.bottom())) + )->setDuration(0)->toggleOn(state->content.value( + ) | rpl::map([=](const Ui::JoinedCountContent &content) { + return (content.count <= 0); + })); +} + +void ManageInviteLinksBox( + not_null box, + not_null peer) { + box->setTitle(tr::lng_group_invite_title()); + + const auto container = box->verticalLayout(); + AddPermanentLinkBlock(container, peer); + Settings::AddDivider(container); + + const auto add = AddCreateLinkButton(container); + add->setClickedCallback([=] { + box->getDelegate()->show(Box(CreateLinkBox, peer)); + }); + + const auto delegate = box->lifetime().make_state< + PeerListContentDelegateSimple + >(); + const auto controller = box->lifetime().make_state(peer); + controller->setStyleOverrides(&st::inviteLinkList); + const auto content = container->add(object_ptr( + container, + controller)); + delegate->setContent(content); + controller->setDelegate(delegate); } diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.h b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.h index 358f82f5f..365071e3a 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.h +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.h @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "ui/layers/generic_box.h" + class PeerData; namespace Ui { @@ -16,3 +18,7 @@ class VerticalLayout; void AddPermanentLinkBlock( not_null container, not_null peer); + +void ManageInviteLinksBox( + not_null box, + not_null peer); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp index 734108fd5..a6a261173 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp @@ -185,7 +185,7 @@ void Controller::createContent() { _wrap.get(), tr::lng_group_invite_manage(), rpl::single(QString()), - [=] { /*ShowEditInviteLinks(_navigation, _peer);*/ }, + [=] { Ui::show(Box(ManageInviteLinksBox, _peer)); }, st::manageGroupButton, &st::infoIconInviteLinks)); AddSkip(_wrap.get()); diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 465ce7260..818d02295 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -839,12 +839,14 @@ inviteLinkField: FlatInput(defaultFlatInput) { height: 44px; textMrg: margins(14px, 12px, 36px, 9px); } +inviteLinkThreeDotsIcon: icon {{ "info/edit/dotsmini", dialogsMenuIconFg }}; +inviteLinkThreeDotsIconOver: icon {{ "info/edit/dotsmini", dialogsMenuIconFgOver }}; inviteLinkThreeDots: IconButton(defaultIconButton) { width: 36px; height: 44px; - icon: icon {{ "info/edit/dotsmini", dialogsMenuIconFg }}; - iconOver: icon {{ "info/edit/dotsmini", dialogsMenuIconFgOver }}; + icon: inviteLinkThreeDotsIcon; + iconOver: inviteLinkThreeDotsIconOver; iconPosition: point(-1px, -1px); rippleAreaSize: 0px; @@ -875,3 +877,43 @@ inviteLinkUserpics: GroupCallUserpics { inviteLinkUserpicsSkip: 8px; inviteLinkJoinedFont: font(14px); inviteLinkJoinedRowPadding: margins(0px, 18px, 0px, 8px); + +inviteLinkCreateSkip: 8px; +inviteLinkCreate: SettingsButton(defaultSettingsButton) { + textFg: lightButtonFg; + textFgOver: lightButtonFgOver; + textBg: windowBg; + textBgOver: windowBgOver; + + font: semiboldFont; + + height: 20px; + padding: margins(58px, 7px, 12px, 5px); + + toggle: infoProfileToggle; + toggleOver: infoProfileToggleOver; + toggleSkip: 22px; + + ripple: defaultRippleAnimation; +} +inviteLinkCreateIcon: icon {{ "info/edit/roundbtn_plus", windowFgActive }}; +inviteLinkCreateIconSize: 20px; +inviteLinkListItem: PeerListItem(defaultPeerListItem) { + button: OutlineButton(defaultPeerListButton) { + font: normalFont; + padding: margins(11px, 5px, 11px, 5px); + } + height: 52px; + photoPosition: point(8px, 6px); + namePosition: point(58px, 6px); + statusPosition: point(58px, 25px); + photoSize: 40px; +} +inviteLinkList: PeerList(defaultPeerList) { + item: inviteLinkListItem; + padding: margins(0px, 4px, 0px, 4px); +} +inviteLinkIconSkip: 7px; +inviteLinkIconStroke: 2px; +inviteLinkIcon: icon {{ "info/edit/links_link", mediaviewFileExtFg }}; +inviteLinkThreeDotsSkip: 8px;