mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 07:07:08 +02:00
Update link rows in Manage Invite Links.
This commit is contained in:
parent
97fb310f54
commit
144bad6c74
3 changed files with 159 additions and 12 deletions
Telegram/SourceFiles
|
@ -123,10 +123,16 @@ auto InviteLinks::prepend(
|
|||
auto &links = i->second;
|
||||
const auto permanent = lookupPermanent(links);
|
||||
if (link.permanent) {
|
||||
auto update = Update{ .peer = peer };
|
||||
if (permanent) {
|
||||
update.was = permanent->link;
|
||||
permanent->revoked = true;
|
||||
}
|
||||
editPermanentLink(peer, link.link);
|
||||
if (permanent) {
|
||||
update.now = *permanent;
|
||||
_updates.fire(std::move(update));
|
||||
}
|
||||
}
|
||||
++links.count;
|
||||
if (permanent && !link.permanent) {
|
||||
|
@ -135,6 +141,7 @@ auto InviteLinks::prepend(
|
|||
links.links.insert(begin(links.links), link);
|
||||
}
|
||||
notify(peer);
|
||||
_updates.fire(Update{ .peer = peer, .now = link });
|
||||
return link;
|
||||
}
|
||||
|
||||
|
@ -205,6 +212,11 @@ void InviteLinks::performEdit(
|
|||
for (const auto &callback : *callbacks) {
|
||||
callback(link);
|
||||
}
|
||||
_updates.fire(Update{
|
||||
.peer = peer,
|
||||
.was = key.link,
|
||||
.now = link
|
||||
});
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
_editCallbacks.erase(key);
|
||||
|
@ -298,6 +310,13 @@ rpl::producer<JoinedByLinkSlice> InviteLinks::joinedFirstSliceValue(
|
|||
}));
|
||||
}
|
||||
|
||||
auto InviteLinks::updates(
|
||||
not_null<PeerData*> peer) const -> rpl::producer<Update> {
|
||||
return _updates.events() | rpl::filter([=](const Update &update) {
|
||||
return update.peer == peer;
|
||||
});
|
||||
}
|
||||
|
||||
void InviteLinks::requestJoinedFirstSlice(LinkKey key) {
|
||||
if (_firstJoinedRequests.contains(key)) {
|
||||
return;
|
||||
|
@ -422,7 +441,6 @@ auto InviteLinks::parse(
|
|||
.usageLimit = data.vusage_limit().value_or_empty(),
|
||||
.usage = data.vusage().value_or_empty(),
|
||||
.permanent = data.is_permanent(),
|
||||
.expired = data.is_expired(),
|
||||
.revoked = data.is_revoked(),
|
||||
};
|
||||
});
|
||||
|
|
|
@ -20,7 +20,6 @@ struct InviteLink {
|
|||
int usageLimit = 0;
|
||||
int usage = 0;
|
||||
bool permanent = false;
|
||||
bool expired = false;
|
||||
bool revoked = false;
|
||||
};
|
||||
|
||||
|
@ -39,12 +38,19 @@ struct JoinedByLinkSlice {
|
|||
int count = 0;
|
||||
};
|
||||
|
||||
struct InviteLinkUpdate {
|
||||
not_null<PeerData*> peer;
|
||||
QString was;
|
||||
std::optional<InviteLink> now;
|
||||
};
|
||||
|
||||
class InviteLinks final {
|
||||
public:
|
||||
explicit InviteLinks(not_null<ApiWrap*> api);
|
||||
|
||||
using Link = InviteLink;
|
||||
using Links = PeerInviteLinks;
|
||||
using Update = InviteLinkUpdate;
|
||||
|
||||
void create(
|
||||
not_null<PeerData*> peer,
|
||||
|
@ -77,6 +83,8 @@ public:
|
|||
not_null<PeerData*> peer,
|
||||
const QString &link,
|
||||
int fullCount);
|
||||
[[nodiscard]] rpl::producer<Update> updates(
|
||||
not_null<PeerData*> peer) const;
|
||||
|
||||
void requestMoreLinks(
|
||||
not_null<PeerData*> peer,
|
||||
|
@ -152,6 +160,8 @@ private:
|
|||
std::vector<Fn<void(Link)>>> _createCallbacks;
|
||||
base::flat_map<LinkKey, std::vector<Fn<void(Link)>>> _editCallbacks;
|
||||
|
||||
rpl::event_stream<Update> _updates;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
|
|
|
@ -53,6 +53,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace {
|
||||
|
||||
constexpr auto kPreloadPages = 2;
|
||||
constexpr auto kFullArcLength = 360 * 16;
|
||||
|
||||
enum class Color {
|
||||
Permanent,
|
||||
|
@ -100,9 +101,11 @@ public:
|
|||
const InviteLinkData &data,
|
||||
TimeId now);
|
||||
|
||||
void update(const InviteLinkData &data);
|
||||
void update(const InviteLinkData &data, TimeId now);
|
||||
void updateExpireProgress(TimeId now);
|
||||
|
||||
[[nodiscard]] InviteLinkData data() const;
|
||||
[[nodiscard]] crl::time updateExpireIn() const;
|
||||
|
||||
QString generateName() override;
|
||||
QString generateShortName() override;
|
||||
|
@ -159,7 +162,6 @@ private:
|
|||
[[nodiscard]] Color ComputeColor(
|
||||
const InviteLinkData &link,
|
||||
float64 progress) {
|
||||
const auto startDate = link.startDate ? link.startDate : link.date;
|
||||
return link.revoked
|
||||
? Color::Revoked
|
||||
: (progress >= 1.)
|
||||
|
@ -171,8 +173,20 @@ private:
|
|||
: Color::Permanent;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString ComputeStatus(const InviteLinkData &link) {
|
||||
return "nothing";
|
||||
[[nodiscard]] QString ComputeStatus(const InviteLinkData &link, TimeId now) {
|
||||
auto result = link.usage
|
||||
? tr::lng_group_invite_joined(tr::now, lt_count_decimal, link.usage)
|
||||
: tr::lng_group_invite_no_joined(tr::now);
|
||||
const auto add = [&](const QString &text) {
|
||||
result += QString::fromUtf8(" \xE2\xB8\xB1 ") + text;
|
||||
};
|
||||
if (link.revoked) {
|
||||
add(tr::lng_group_invite_link_revoked(tr::now));
|
||||
} else if ((link.usageLimit > 0 && link.usage >= link.usageLimit)
|
||||
|| (link.expireDate > 0 && now >= link.expireDate)) {
|
||||
add(tr::lng_group_invite_link_expired(tr::now));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CopyLink(const QString &link) {
|
||||
|
@ -338,21 +352,45 @@ Row::Row(
|
|||
, _data(data)
|
||||
, _progressTillExpire(ComputeProgress(data, now))
|
||||
, _color(ComputeColor(data, _progressTillExpire)) {
|
||||
setCustomStatus(ComputeStatus(data));
|
||||
setCustomStatus(ComputeStatus(data, now));
|
||||
}
|
||||
|
||||
void Row::update(const InviteLinkData &data) {
|
||||
void Row::update(const InviteLinkData &data, TimeId now) {
|
||||
_data = data;
|
||||
_progressTillExpire = ComputeProgress(data, base::unixtime::now());
|
||||
_progressTillExpire = ComputeProgress(data, now);
|
||||
_color = ComputeColor(data, _progressTillExpire);
|
||||
setCustomStatus(ComputeStatus(data));
|
||||
setCustomStatus(ComputeStatus(data, now));
|
||||
_delegate->rowUpdateRow(this);
|
||||
}
|
||||
|
||||
void Row::updateExpireProgress(TimeId now) {
|
||||
const auto updated = ComputeProgress(_data, now);
|
||||
if (std::round(_progressTillExpire * 360) != std::round(updated * 360)) {
|
||||
_progressTillExpire = updated;
|
||||
const auto color = ComputeColor(_data, _progressTillExpire);
|
||||
if (_color != color) {
|
||||
_color = color;
|
||||
setCustomStatus(ComputeStatus(_data, now));
|
||||
}
|
||||
_delegate->rowUpdateRow(this);
|
||||
}
|
||||
}
|
||||
|
||||
InviteLinkData Row::data() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
crl::time Row::updateExpireIn() const {
|
||||
if (_color != Color::Expiring && _color != Color::ExpireSoon) {
|
||||
return 0;
|
||||
}
|
||||
const auto start = _data.startDate ? _data.startDate : _data.date;
|
||||
if (_data.expireDate <= start) {
|
||||
return 0;
|
||||
}
|
||||
return std::round((_data.expireDate - start) * crl::time(1000) / 720.);
|
||||
}
|
||||
|
||||
QString Row::generateName() {
|
||||
auto result = _data.link;
|
||||
return result.replace(qstr("https://"), QString());
|
||||
|
@ -425,6 +463,13 @@ public:
|
|||
|
||||
private:
|
||||
void appendRow(const InviteLinkData &data, TimeId now);
|
||||
void prependRow(const InviteLinkData &data, TimeId now);
|
||||
void updateRow(const InviteLinkData &data, TimeId now);
|
||||
bool removeRow(const QString &link);
|
||||
|
||||
void checkExpiringTimer(not_null<Row*> row);
|
||||
void expiringProgressTimer();
|
||||
|
||||
[[nodiscard]] base::unique_qptr<Ui::PopupMenu> createRowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row);
|
||||
|
@ -433,6 +478,9 @@ private:
|
|||
bool _revoked = false;
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
|
||||
base::flat_set<not_null<Row*>> _expiringRows;
|
||||
base::Timer _updateExpiringTimer;
|
||||
|
||||
std::array<QImage, int(Color::Count)> _icons;
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
|
@ -440,13 +488,31 @@ private:
|
|||
|
||||
Controller::Controller(not_null<PeerData*> peer, bool revoked)
|
||||
: _peer(peer)
|
||||
, _revoked(revoked) {
|
||||
, _revoked(revoked)
|
||||
, _updateExpiringTimer([=] { expiringProgressTimer(); }) {
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
for (auto &image : _icons) {
|
||||
image = QImage();
|
||||
}
|
||||
}, _lifetime);
|
||||
|
||||
peer->session().api().inviteLinks().updates(
|
||||
peer
|
||||
) | rpl::start_with_next([=](const Api::InviteLinkUpdate &update) {
|
||||
const auto now = base::unixtime::now();
|
||||
if (!update.now
|
||||
|| (!update.was.isEmpty() && update.now->revoked != _revoked)) {
|
||||
if (removeRow(update.was)) {
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
} else if (update.was.isEmpty()) {
|
||||
prependRow(*update.now, now);
|
||||
delegate()->peerListRefreshRows();
|
||||
} else {
|
||||
updateRow(*update.now, now);
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void Controller::prepare() {
|
||||
|
@ -538,6 +604,60 @@ void Controller::appendRow(const InviteLinkData &data, TimeId now) {
|
|||
delegate()->peerListAppendRow(std::make_unique<Row>(this, data, now));
|
||||
}
|
||||
|
||||
void Controller::prependRow(const InviteLinkData &data, TimeId now) {
|
||||
delegate()->peerListPrependRow(std::make_unique<Row>(this, data, now));
|
||||
}
|
||||
|
||||
void Controller::updateRow(const InviteLinkData &data, TimeId now) {
|
||||
if (const auto row = delegate()->peerListFindRow(ComputeRowId(data))) {
|
||||
const auto real = static_cast<Row*>(row);
|
||||
real->update(data, now);
|
||||
checkExpiringTimer(real);
|
||||
delegate()->peerListUpdateRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
bool Controller::removeRow(const QString &link) {
|
||||
if (const auto row = delegate()->peerListFindRow(ComputeRowId(link))) {
|
||||
delegate()->peerListRemoveRow(row);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Controller::checkExpiringTimer(not_null<Row*> row) {
|
||||
const auto updateIn = row->updateExpireIn();
|
||||
if (updateIn > 0) {
|
||||
_expiringRows.emplace(row);
|
||||
if (!_updateExpiringTimer.isActive()
|
||||
|| updateIn < _updateExpiringTimer.remainingTime()) {
|
||||
_updateExpiringTimer.callOnce(updateIn);
|
||||
}
|
||||
} else {
|
||||
_expiringRows.remove(row);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::expiringProgressTimer() {
|
||||
const auto now = base::unixtime::now();
|
||||
auto minimalIn = 0;
|
||||
for (auto i = begin(_expiringRows); i != end(_expiringRows);) {
|
||||
(*i)->updateExpireProgress(now);
|
||||
const auto updateIn = (*i)->updateExpireIn();
|
||||
if (!updateIn) {
|
||||
i = _expiringRows.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
if (!minimalIn || minimalIn > updateIn) {
|
||||
minimalIn = updateIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minimalIn) {
|
||||
_updateExpiringTimer.callOnce(minimalIn);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::rowUpdateRow(not_null<Row*> row) {
|
||||
delegate()->peerListUpdateRow(row);
|
||||
}
|
||||
|
@ -578,7 +698,6 @@ void Controller::rowPaintIcon(
|
|||
}
|
||||
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);
|
||||
|
|
Loading…
Add table
Reference in a new issue