mark more channels as unread properly

This commit is contained in:
ouwou
2021-12-25 02:37:31 -05:00
parent 145504bdd6
commit 41d80af128
5 changed files with 66 additions and 4 deletions

View File

@@ -2253,6 +2253,7 @@ void DiscordClient::StoreMessageData(Message &msg) {
// some notes for myself
// a read channel is determined by checking if the channel object's last message id is equal to the read state's last message id
// channels without entries are also unread
// here the absence of an entry in m_unread indicates a read channel and the value is only the mention count since the message doesnt matter
// no entry.id cannot be a guild even though sometimes it looks like it
void DiscordClient::HandleReadyReadState(const ReadyEventData &data) {
@@ -2270,6 +2271,26 @@ void DiscordClient::HandleReadyReadState(const ReadyEventData &data) {
if (it->second > entry.LastMessageID)
m_unread[entry.ID] = entry.MentionCount;
}
// channels that arent in the read state are considered unread
for (const auto &guild : data.Guilds) {
if (!guild.JoinedAt.has_value()) continue; // doubt this can happen but whatever
const auto joined_at = Snowflake::FromISO8601(*guild.JoinedAt);
for (const auto &channel : *guild.Channels) {
if (channel.LastMessageID.has_value()) {
// unread messages from before you joined dont count as unread
if (*channel.LastMessageID < joined_at) continue;
if (std::find_if(data.ReadState.Entries.begin(), data.ReadState.Entries.end(), [id = channel.ID](const ReadStateEntry &e) {
return e.ID == id;
}) == data.ReadState.Entries.end()) {
// cant be unread if u cant even see the channel
// better to check here since HasChannelPermission hits the store
if (HasChannelPermission(GetUserData().ID, channel.ID, Permission::VIEW_CHANNEL))
m_unread[channel.ID] = 0;
}
}
}
}
}
void DiscordClient::HandleReadyGuildSettings(const ReadyEventData &data) {

View File

@@ -1,7 +1,8 @@
#include "snowflake.hpp"
#include "util.hpp"
#include <chrono>
#include <ctime>
#include <iomanip>
#include <chrono>
constexpr static uint64_t DiscordEpochSeconds = 1420070400;
@@ -14,13 +15,13 @@ Snowflake::Snowflake(uint64_t n)
: m_num(n) {}
Snowflake::Snowflake(const std::string &str) {
if (str.size())
if (!str.empty())
m_num = std::stoull(str);
else
m_num = Invalid;
}
Snowflake::Snowflake(const Glib::ustring &str) {
if (str.size())
if (!str.empty())
m_num = std::strtoull(str.c_str(), nullptr, 10);
else
m_num = Invalid;
@@ -38,6 +39,14 @@ Snowflake Snowflake::FromNow() {
return snowflake;
}
Snowflake Snowflake::FromISO8601(std::string_view ts) {
int yr, mon, day, hr, min, sec, tzhr, tzmin;
float milli;
std::sscanf(ts.data(), "%d-%d-%dT%d:%d:%d%f+%d:%d",
&yr, &mon, &day, &hr, &min, &sec, &milli, &tzhr, &tzmin);
return SecondsInterval * (util::TimeToEpoch(yr, mon, day, hr, min, sec) - DiscordEpochSeconds) + static_cast<uint64_t>(milli * static_cast<float>(SecondsInterval));
}
bool Snowflake::IsValid() const {
return m_num != Invalid;
}

View File

@@ -10,6 +10,7 @@ struct Snowflake {
Snowflake(const Glib::ustring &str);
static Snowflake FromNow(); // not thread safe
static Snowflake FromISO8601(std::string_view ts);
bool IsValid() const;
std::string GetLocalTimestamp() const;
@@ -26,7 +27,7 @@ struct Snowflake {
return m_num;
}
const static Snowflake Invalid; // makes sense to me
const static Snowflake Invalid; // makes sense to me
const static uint64_t SecondsInterval = 4194304000ULL; // the "difference" between two snowflakes one second apart
friend void from_json(const nlohmann::json &j, Snowflake &s);

View File

@@ -1,4 +1,5 @@
#include "util.hpp"
#include <array>
#include <filesystem>
Semaphore::Semaphore(int count)
@@ -215,3 +216,31 @@ bool util::IsFile(std::string_view path) {
if (ec) return false;
return status.type() == std::filesystem::file_type::regular;
}
constexpr bool IsLeapYear(int year) {
if (year % 4 != 0) return false;
if (year % 100 != 0) return true;
return (year % 400) == 0;
}
constexpr static int SecsPerMinute = 60;
constexpr static int SecsPerHour = 3600;
constexpr static int SecsPerDay = 86400;
constexpr static std::array<int, 12> DaysOfMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// may god smite whoever is responsible for the absolutely abominable api that is C time functions
// i shouldnt have to write this. mktime ALMOST works but it adds the current timezone offset. WHY???
uint64_t util::TimeToEpoch(int year, int month, int day, int hour, int minute, int seconds) {
uint64_t secs = 0;
for (int y = 1970; y < year; ++y)
secs += (IsLeapYear(y) ? 366 : 365) * SecsPerDay;
for (int m = 1; m < month; ++m) {
secs += DaysOfMonth[m - 1] * SecsPerDay;
if (m == 2 && IsLeapYear(year)) secs += SecsPerDay;
}
secs += (day - 1) * SecsPerDay;
secs += hour * SecsPerHour;
secs += minute * SecsPerMinute;
secs += seconds;
return secs;
}

View File

@@ -27,6 +27,8 @@ struct is_optional<::std::optional<T>> : ::std::true_type {};
bool IsFolder(std::string_view path);
bool IsFile(std::string_view path);
uint64_t TimeToEpoch(int year, int month, int day, int hour, int minute, int seconds);
} // namespace util
class Semaphore {