mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Check listened / viewed for voice / video messages.
This commit is contained in:
parent
eb1874566b
commit
fa5e66a736
4 changed files with 86 additions and 26 deletions
|
@ -1707,10 +1707,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_context_seen_loading" = "Loading...";
|
"lng_context_seen_loading" = "Loading...";
|
||||||
"lng_context_seen_text#one" = "{count} Seen";
|
"lng_context_seen_text#one" = "{count} Seen";
|
||||||
"lng_context_seen_text#other" = "{count} Seen";
|
"lng_context_seen_text#other" = "{count} Seen";
|
||||||
|
"lng_context_seen_text_none" = "Nobody Viewed";
|
||||||
"lng_context_seen_listened#one" = "{count} Listened";
|
"lng_context_seen_listened#one" = "{count} Listened";
|
||||||
"lng_context_seen_listened#other" = "{count} Listened";
|
"lng_context_seen_listened#other" = "{count} Listened";
|
||||||
|
"lng_context_seen_listened_none" = "Nobody Listened";
|
||||||
"lng_context_seen_watched#one" = "{count} Watched";
|
"lng_context_seen_watched#one" = "{count} Watched";
|
||||||
"lng_context_seen_watched#other" = "{count} Watched";
|
"lng_context_seen_watched#other" = "{count} Watched";
|
||||||
|
"lng_context_seen_watched_none" = "Nobody Watched";
|
||||||
|
|
||||||
"lng_send_image_empty" = "Could not send an empty file: {name}";
|
"lng_send_image_empty" = "Could not send an empty file: {name}";
|
||||||
"lng_send_image_too_large" = "Could not send a file, because it is larger than 1500 MB: {name}";
|
"lng_send_image_too_large" = "Could not send a file, because it is larger than 1500 MB: {name}";
|
||||||
|
|
|
@ -12,9 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_chat.h"
|
#include "data/data_chat.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_media_types.h"
|
||||||
#include "main/main_app_config.h"
|
#include "main/main_app_config.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_account.h"
|
#include "main/main_account.h"
|
||||||
|
@ -26,6 +28,9 @@ namespace Api {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct Cached {
|
struct Cached {
|
||||||
|
explicit Cached(UserId unknownFlag)
|
||||||
|
: list(std::vector<UserId>{ unknownFlag }) {
|
||||||
|
}
|
||||||
rpl::variable<std::vector<UserId>> list;
|
rpl::variable<std::vector<UserId>> list;
|
||||||
mtpRequestId requestId = 0;
|
mtpRequestId requestId = 0;
|
||||||
};
|
};
|
||||||
|
@ -33,6 +38,17 @@ struct Cached {
|
||||||
struct Context {
|
struct Context {
|
||||||
base::flat_map<not_null<HistoryItem*>, Cached> cached;
|
base::flat_map<not_null<HistoryItem*>, Cached> cached;
|
||||||
base::flat_map<not_null<Main::Session*>, rpl::lifetime> subscriptions;
|
base::flat_map<not_null<Main::Session*>, rpl::lifetime> subscriptions;
|
||||||
|
|
||||||
|
[[nodiscard]] Cached &cache(not_null<HistoryItem*> item) {
|
||||||
|
const auto i = cached.find(item);
|
||||||
|
if (i != end(cached)) {
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
return cached.emplace(
|
||||||
|
item,
|
||||||
|
Cached(item->history()->session().userId())
|
||||||
|
).first->second;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] auto Contexts()
|
[[nodiscard]] auto Contexts()
|
||||||
|
@ -65,10 +81,39 @@ struct Context {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool ListUnknown(
|
||||||
|
const std::vector<UserId> &list,
|
||||||
|
not_null<HistoryItem*> item) {
|
||||||
|
return (list.size() == 1)
|
||||||
|
&& (list.front() == item->history()->session().userId());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Ui::WhoReadType DetectType(not_null<HistoryItem*> item) {
|
||||||
|
if (const auto media = item->media()) {
|
||||||
|
if (!media->webpage()) {
|
||||||
|
if (const auto document = media->document()) {
|
||||||
|
if (document->isVoiceMessage()) {
|
||||||
|
return Ui::WhoReadType::Listened;
|
||||||
|
} else if (document->isVideoMessage()) {
|
||||||
|
return Ui::WhoReadType::Watched;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ui::WhoReadType::Seen;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool WhoReadExists(not_null<HistoryItem*> item) {
|
bool WhoReadExists(not_null<HistoryItem*> item) {
|
||||||
if (!item->out() || item->unread()) {
|
if (!item->out()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto type = DetectType(item);
|
||||||
|
const auto unseen = (type == Ui::WhoReadType::Seen)
|
||||||
|
? item->unread()
|
||||||
|
: item->isUnreadMedia();
|
||||||
|
if (unseen) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto history = item->history();
|
const auto history = item->history();
|
||||||
|
@ -122,38 +167,37 @@ rpl::producer<std::vector<UserId>> WhoReadIds(
|
||||||
context->cached.erase(i);
|
context->cached.erase(i);
|
||||||
}, context->subscriptions[session]);
|
}, context->subscriptions[session]);
|
||||||
}
|
}
|
||||||
auto &cache = context->cached[item];
|
auto &entry = context->cache(item);
|
||||||
if (!cache.requestId) {
|
if (!entry.requestId) {
|
||||||
const auto makeEmpty = [=] {
|
const auto makeEmpty = [=] {
|
||||||
// Special value that marks a validated empty list.
|
// Special value that marks a validated empty list.
|
||||||
return std::vector<UserId>{
|
return std::vector<UserId>{
|
||||||
item->history()->session().userId()
|
item->history()->session().userId()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
cache.requestId = session->api().request(
|
entry.requestId = session->api().request(
|
||||||
MTPmessages_GetMessageReadParticipants(
|
MTPmessages_GetMessageReadParticipants(
|
||||||
item->history()->peer->input,
|
item->history()->peer->input,
|
||||||
MTP_int(item->id)
|
MTP_int(item->id)
|
||||||
)
|
)
|
||||||
).done([=](const MTPVector<MTPlong> &result) {
|
).done([=](const MTPVector<MTPlong> &result) {
|
||||||
|
auto &entry = context->cache(item);
|
||||||
|
entry.requestId = 0;
|
||||||
auto users = std::vector<UserId>();
|
auto users = std::vector<UserId>();
|
||||||
users.reserve(std::max(result.v.size(), 1));
|
users.reserve(std::max(result.v.size(), 1));
|
||||||
for (const auto &id : result.v) {
|
for (const auto &id : result.v) {
|
||||||
users.push_back(UserId(id));
|
users.push_back(UserId(id));
|
||||||
}
|
}
|
||||||
if (users.empty()) {
|
entry.list = std::move(users);
|
||||||
|
|
||||||
}
|
|
||||||
context->cached[item].list = users.empty()
|
|
||||||
? makeEmpty()
|
|
||||||
: std::move(users);
|
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
if (context->cached[item].list.current().empty()) {
|
auto &entry = context->cache(item);
|
||||||
context->cached[item].list = makeEmpty();
|
entry.requestId = 0;
|
||||||
|
if (ListUnknown(entry.list.current(), item)) {
|
||||||
|
entry.list = std::vector<UserId>();
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
return cache.list.value().start_existing(consumer);
|
return entry.list.value().start_existing(consumer);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,14 +209,9 @@ rpl::producer<Ui::WhoReadContent> WhoRead(
|
||||||
context
|
context
|
||||||
) | rpl::map([=](const std::vector<UserId> &users) {
|
) | rpl::map([=](const std::vector<UserId> &users) {
|
||||||
const auto owner = &item->history()->owner();
|
const auto owner = &item->history()->owner();
|
||||||
if (users.empty()) {
|
if (ListUnknown(users, item)) {
|
||||||
return Ui::WhoReadContent{ .unknown = true };
|
return Ui::WhoReadContent{ .unknown = true };
|
||||||
}
|
}
|
||||||
const auto nobody = (users.size() == 1)
|
|
||||||
&& (users.front() == owner->session().userId());
|
|
||||||
if (nobody) {
|
|
||||||
return Ui::WhoReadContent();
|
|
||||||
}
|
|
||||||
auto participants = ranges::views::all(
|
auto participants = ranges::views::all(
|
||||||
users
|
users
|
||||||
) | ranges::views::transform([&](UserId id) {
|
) | ranges::views::transform([&](UserId id) {
|
||||||
|
@ -187,6 +226,7 @@ rpl::producer<Ui::WhoReadContent> WhoRead(
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
return Ui::WhoReadContent{
|
return Ui::WhoReadContent{
|
||||||
.participants = std::move(participants),
|
.participants = std::move(participants),
|
||||||
|
.type = DetectType(item),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,15 @@ Action::Action(
|
||||||
paint(p);
|
paint(p);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
clicks(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
if (_content.participants.size() == 1) {
|
||||||
|
if (const auto onstack = _participantChosen) {
|
||||||
|
onstack(_content.participants.front().id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
enableMouseSelecting();
|
enableMouseSelecting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,9 +138,10 @@ void Action::resolveMinWidth() {
|
||||||
const auto width = [&](const QString &text) {
|
const auto width = [&](const QString &text) {
|
||||||
return _st.itemStyle.font->width(text);
|
return _st.itemStyle.font->width(text);
|
||||||
};
|
};
|
||||||
const auto maxTextWidth = std::max(
|
const auto maxTextWidth = std::max({
|
||||||
width(tr::lng_context_seen_text(tr::now, lt_count, 999)),
|
width(tr::lng_context_seen_text(tr::now, lt_count, 999)),
|
||||||
width(tr::lng_context_seen_listened(tr::now, lt_count, 999)));
|
width(tr::lng_context_seen_listened(tr::now, lt_count, 999)),
|
||||||
|
width(tr::lng_context_seen_watched(tr::now, lt_count, 999)) });
|
||||||
const auto maxWidth = _st.itemPadding.left()
|
const auto maxWidth = _st.itemPadding.left()
|
||||||
+ maxIconWidth
|
+ maxIconWidth
|
||||||
+ maxTextWidth
|
+ maxTextWidth
|
||||||
|
@ -160,7 +170,7 @@ void Action::updateUserpicsFromContent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::populateSubmenu() {
|
void Action::populateSubmenu() {
|
||||||
if (_content.participants.empty()) {
|
if (_content.participants.size() < 2) {
|
||||||
_parentMenu->removeSubmenu(action());
|
_parentMenu->removeSubmenu(action());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -172,6 +182,7 @@ void Action::populateSubmenu() {
|
||||||
};
|
};
|
||||||
submenu->addAction(participant.name, chosen);
|
submenu->addAction(participant.name, chosen);
|
||||||
}
|
}
|
||||||
|
_parentMenu->checkSubmenuShow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::paint(Painter &p) {
|
void Action::paint(Painter &p) {
|
||||||
|
@ -206,10 +217,16 @@ void Action::refreshText() {
|
||||||
: (count == 1)
|
: (count == 1)
|
||||||
? _content.participants.front().name
|
? _content.participants.front().name
|
||||||
: (_content.type == WhoReadType::Watched)
|
: (_content.type == WhoReadType::Watched)
|
||||||
? tr::lng_context_seen_watched(tr::now, lt_count, count)
|
? (count
|
||||||
|
? tr::lng_context_seen_watched(tr::now, lt_count, count)
|
||||||
|
: tr::lng_context_seen_watched_none(tr::now))
|
||||||
: (_content.type == WhoReadType::Listened)
|
: (_content.type == WhoReadType::Listened)
|
||||||
? tr::lng_context_seen_listened(tr::now, lt_count, count)
|
? (count
|
||||||
: tr::lng_context_seen_text(tr::now, lt_count, count)) },
|
? tr::lng_context_seen_listened(tr::now, lt_count, count)
|
||||||
|
: tr::lng_context_seen_listened_none(tr::now))
|
||||||
|
: (count
|
||||||
|
? tr::lng_context_seen_text(tr::now, lt_count, count)
|
||||||
|
: tr::lng_context_seen_text_none(tr::now))) },
|
||||||
MenuTextOptions);
|
MenuTextOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 6651d9f9b6fb7ebc9d18e6b3429862477d891b2e
|
Subproject commit f4cf3094c29e445256bd1c198323d393be4405c1
|
Loading…
Add table
Reference in a new issue