forked from OpenGamers/abaddon
mark more channels as unread properly
This commit is contained in:
@@ -2253,6 +2253,7 @@ void DiscordClient::StoreMessageData(Message &msg) {
|
|||||||
|
|
||||||
// some notes for myself
|
// 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
|
// 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
|
// 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
|
// no entry.id cannot be a guild even though sometimes it looks like it
|
||||||
void DiscordClient::HandleReadyReadState(const ReadyEventData &data) {
|
void DiscordClient::HandleReadyReadState(const ReadyEventData &data) {
|
||||||
@@ -2270,6 +2271,26 @@ void DiscordClient::HandleReadyReadState(const ReadyEventData &data) {
|
|||||||
if (it->second > entry.LastMessageID)
|
if (it->second > entry.LastMessageID)
|
||||||
m_unread[entry.ID] = entry.MentionCount;
|
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) {
|
void DiscordClient::HandleReadyGuildSettings(const ReadyEventData &data) {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#include "snowflake.hpp"
|
#include "snowflake.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
constexpr static uint64_t DiscordEpochSeconds = 1420070400;
|
constexpr static uint64_t DiscordEpochSeconds = 1420070400;
|
||||||
|
|
||||||
@@ -14,13 +15,13 @@ Snowflake::Snowflake(uint64_t n)
|
|||||||
: m_num(n) {}
|
: m_num(n) {}
|
||||||
|
|
||||||
Snowflake::Snowflake(const std::string &str) {
|
Snowflake::Snowflake(const std::string &str) {
|
||||||
if (str.size())
|
if (!str.empty())
|
||||||
m_num = std::stoull(str);
|
m_num = std::stoull(str);
|
||||||
else
|
else
|
||||||
m_num = Invalid;
|
m_num = Invalid;
|
||||||
}
|
}
|
||||||
Snowflake::Snowflake(const Glib::ustring &str) {
|
Snowflake::Snowflake(const Glib::ustring &str) {
|
||||||
if (str.size())
|
if (!str.empty())
|
||||||
m_num = std::strtoull(str.c_str(), nullptr, 10);
|
m_num = std::strtoull(str.c_str(), nullptr, 10);
|
||||||
else
|
else
|
||||||
m_num = Invalid;
|
m_num = Invalid;
|
||||||
@@ -38,6 +39,14 @@ Snowflake Snowflake::FromNow() {
|
|||||||
return snowflake;
|
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 {
|
bool Snowflake::IsValid() const {
|
||||||
return m_num != Invalid;
|
return m_num != Invalid;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ struct Snowflake {
|
|||||||
Snowflake(const Glib::ustring &str);
|
Snowflake(const Glib::ustring &str);
|
||||||
|
|
||||||
static Snowflake FromNow(); // not thread safe
|
static Snowflake FromNow(); // not thread safe
|
||||||
|
static Snowflake FromISO8601(std::string_view ts);
|
||||||
|
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
std::string GetLocalTimestamp() const;
|
std::string GetLocalTimestamp() const;
|
||||||
@@ -26,7 +27,7 @@ struct Snowflake {
|
|||||||
return m_num;
|
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
|
const static uint64_t SecondsInterval = 4194304000ULL; // the "difference" between two snowflakes one second apart
|
||||||
|
|
||||||
friend void from_json(const nlohmann::json &j, Snowflake &s);
|
friend void from_json(const nlohmann::json &j, Snowflake &s);
|
||||||
|
|||||||
29
src/util.cpp
29
src/util.cpp
@@ -1,4 +1,5 @@
|
|||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
#include <array>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
Semaphore::Semaphore(int count)
|
Semaphore::Semaphore(int count)
|
||||||
@@ -215,3 +216,31 @@ bool util::IsFile(std::string_view path) {
|
|||||||
if (ec) return false;
|
if (ec) return false;
|
||||||
return status.type() == std::filesystem::file_type::regular;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ struct is_optional<::std::optional<T>> : ::std::true_type {};
|
|||||||
bool IsFolder(std::string_view path);
|
bool IsFolder(std::string_view path);
|
||||||
|
|
||||||
bool IsFile(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
|
} // namespace util
|
||||||
|
|
||||||
class Semaphore {
|
class Semaphore {
|
||||||
|
|||||||
Reference in New Issue
Block a user