feat: new message history viewer initial

fix: use Qt formatting

kanged from `admin_log` and cleaned up a bit
This commit is contained in:
ZavaruKitsu 2023-09-14 17:36:14 +03:00
parent ba93a50062
commit e1babcf69a
56 changed files with 6953 additions and 2561 deletions

View file

@ -102,6 +102,8 @@ PRIVATE
ayu/ayu_lang.cpp
ayu/ayu_lang.h
ayu/ayu_constants.h
ayu/utils/ayu_mapper.cpp
ayu/utils/ayu_mapper.h
ayu/utils/telegram_helpers.cpp
ayu/utils/telegram_helpers.h
ayu/utils/windows_utils.cpp
@ -118,6 +120,12 @@ PRIVATE
ayu/ui/settings/settings_ayu.h
ayu/ui/context_menu/context_menu.cpp
ayu/ui/context_menu/context_menu.h
ayu/ui/sections/edited/edited_log_inner.cpp
ayu/ui/sections/edited/edited_log_inner.h
ayu/ui/sections/edited/edited_log_item.cpp
ayu/ui/sections/edited/edited_log_item.h
ayu/ui/sections/edited/edited_log_section.cpp
ayu/ui/sections/edited/edited_log_section.h
ayu/ui/boxes/voice_confirmation_box.cpp
ayu/ui/boxes/voice_confirmation_box.h
ayu/ui/boxes/message_history_box.cpp

View file

@ -4,11 +4,13 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
// https://github.com/AyuGram/AyuGram4A/blob/rewrite/TMessagesProj/src/main/java/com/radolyn/ayugram/AyuConstants.java
// https://github.com/AyuGram/AyuGram4AX/blob/rewrite/TMessagesProj/src/main/java/com/radolyn/ayugram/AyuConstants.java
constexpr int DOCUMENT_TYPE_NONE = 0;
constexpr int DOCUMENT_TYPE_PHOTO = 1;
constexpr int DOCUMENT_TYPE_STICKER = 2;
constexpr int DOCUMENT_TYPE_FILE = 3;

View file

@ -12,7 +12,7 @@
#include "core/core_settings.h"
#include "lang/lang_instance.h"
CustomLangPack* CustomLangPack::instance = nullptr;
CustomLangPack *CustomLangPack::instance = nullptr;
CustomLangPack::CustomLangPack() = default;
@ -22,39 +22,35 @@ void CustomLangPack::initInstance()
instance = new CustomLangPack;
}
CustomLangPack* CustomLangPack::currentInstance()
CustomLangPack *CustomLangPack::currentInstance()
{
return instance;
}
void CustomLangPack::fetchCustomLangPack(const QString& langPackId, const QString& langPackBaseId)
void CustomLangPack::fetchCustomLangPack(const QString &langPackId, const QString &langPackBaseId)
{
LOG(("Current Language pack ID: %1, Base ID: %2").arg(langPackId, langPackBaseId));
auto finalLangPackId = langPackId;
if (finalLangPackId == qsl("pt-br"))
{
if (finalLangPackId == qsl("pt-br")) {
// meh
finalLangPackId = qsl("pt");
}
const auto proxy = Core::App().settings().proxy().isEnabled()
? Core::App().settings().proxy().selected()
: MTP::ProxyData();
if (proxy.type == MTP::ProxyData::Type::Socks5 || proxy.type == MTP::ProxyData::Type::Http)
{
? Core::App().settings().proxy().selected()
: MTP::ProxyData();
if (proxy.type == MTP::ProxyData::Type::Socks5 || proxy.type == MTP::ProxyData::Type::Http) {
QNetworkProxy LocaleProxy = ToNetworkProxy(ToDirectIpProxy(proxy));
networkManager.setProxy(LocaleProxy);
}
QUrl url;
if (!finalLangPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback)
{
if (!finalLangPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback) {
url.setUrl(qsl("https://raw.githubusercontent.com/AyuGram/Languages/l10n_main/values/langs/%1/Shared.json").arg(
finalLangPackId));
}
else
{
else {
url.setUrl(qsl("https://raw.githubusercontent.com/AyuGram/Languages/l10n_main/values/langs/%1/Shared.json").arg(
needFallback ? langPackBaseId : finalLangPackId));
}
@ -73,24 +69,20 @@ void CustomLangPack::fetchFinished()
QString langPackId = Lang::GetInstance().id();
auto statusCode = _chkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode == 404 && !langPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback)
{
if (statusCode == 404 && !langPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback) {
LOG(("AyuGram Language pack not found! Fallback to main language: %1...").arg(langPackBaseId));
needFallback = true;
_chkReply->disconnect();
fetchCustomLangPack("", langPackBaseId);
}
else
{
else {
QByteArray result = _chkReply->readAll().trimmed();
QJsonParseError error{};
QJsonDocument str = QJsonDocument::fromJson(result, &error);
if (error.error == QJsonParseError::NoError)
{
if (error.error == QJsonParseError::NoError) {
parseLangFile(str);
}
else
{
else {
LOG(("Incorrect JSON File. Fallback to default language: English..."));
loadDefaultLangFile();
}
@ -103,20 +95,17 @@ void CustomLangPack::fetchError(QNetworkReply::NetworkError e)
{
LOG(("Network error: %1").arg(e));
if (e == QNetworkReply::NetworkError::ContentNotFoundError)
{
if (e == QNetworkReply::NetworkError::ContentNotFoundError) {
QString langPackBaseId = Lang::GetInstance().baseId();
QString langPackId = Lang::GetInstance().id();
if (!langPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback)
{
if (!langPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback) {
LOG(("AyuGram Language pack not found! Fallback to main language: %1...").arg(langPackBaseId));
needFallback = true;
_chkReply->disconnect();
fetchCustomLangPack("", langPackBaseId);
}
else
{
else {
LOG(("AyuGram Language pack not found! Fallback to default language: English..."));
loadDefaultLangFile();
_chkReply = nullptr;
@ -127,12 +116,10 @@ void CustomLangPack::fetchError(QNetworkReply::NetworkError e)
void CustomLangPack::loadDefaultLangFile()
{
QFile file(":/localization/en.json");
if (file.open(QIODevice::ReadOnly))
{
if (file.open(QIODevice::ReadOnly)) {
QJsonDocument str = QJsonDocument::fromJson(file.readAll());
QJsonObject json = str.object();
for (const QString& key : json.keys())
{
for (const QString &key : json.keys()) {
Lang::GetInstance().applyValue(key.toUtf8(), json.value(key).toString().toUtf8());
}
Lang::GetInstance().updatePluralRules();
@ -143,15 +130,13 @@ void CustomLangPack::loadDefaultLangFile()
void CustomLangPack::parseLangFile(QJsonDocument str)
{
QJsonObject json = str.object();
for (const QString& brokenKey : json.keys())
{
for (const QString &brokenKey : json.keys()) {
auto key = qsl("ayu_") + brokenKey;
auto val = json.value(brokenKey).toString().replace(qsl("&"), qsl("&")).toUtf8();
Lang::GetInstance().resetValue(key.toUtf8());
Lang::GetInstance().applyValue(key.toUtf8(), val);
if (key.contains("#other"))
{
if (key.contains("#other")) {
Lang::GetInstance().resetValue(key.toUtf8().replace("#other", "#few"));
Lang::GetInstance().resetValue(key.toUtf8().replace("#other", "#few"));
Lang::GetInstance().applyValue(key.toUtf8().replace("#other", "#few"), val);

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include <QtNetwork/QNetworkReply>
@ -12,18 +11,18 @@
class CustomLangPack : public QObject
{
Q_OBJECT
Q_OBJECT
Q_DISABLE_COPY(CustomLangPack)
public:
static CustomLangPack* currentInstance();
static CustomLangPack *currentInstance();
static void initInstance();
static CustomLangPack* instance;
static CustomLangPack *instance;
void fetchCustomLangPack(const QString& langPackId, const QString& langPackBaseId);
void fetchCustomLangPack(const QString &langPackId, const QString &langPackBaseId);
void loadDefaultLangFile();
@ -40,6 +39,6 @@ private:
~CustomLangPack() override = default;
QNetworkAccessManager networkManager;
QNetworkReply* _chkReply = nullptr;
QNetworkReply *_chkReply = nullptr;
bool needFallback = false;
};

View file

@ -14,301 +14,315 @@ using json = nlohmann::json;
namespace AyuSettings
{
const QString filename = "tdata/ayu_settings.json";
std::optional<AyuGramSettings> settings = std::nullopt;
rpl::variable<bool> sendReadMessagesReactive;
rpl::variable<bool> sendReadStoriesReactive;
rpl::variable<bool> sendOnlinePacketsReactive;
rpl::variable<bool> sendUploadProgressReactive;
rpl::variable<bool> sendOfflinePacketAfterOnlineReactive;
const QString filename = "tdata/ayu_settings.json";
rpl::variable<QString> deletedMarkReactive;
rpl::variable<QString> editedMarkReactive;
rpl::variable<int> showPeerIdReactive;
std::optional<AyuGramSettings> settings = std::nullopt;
rpl::variable<bool> ghostModeEnabled;
rpl::variable<bool> sendReadMessagesReactive;
rpl::lifetime lifetime = rpl::lifetime();
rpl::variable<bool> sendReadStoriesReactive;
bool ghostModeEnabled_util(AyuGramSettings& settingsUtil)
{
return
!settingsUtil.sendReadMessages
rpl::variable<bool> sendOnlinePacketsReactive;
rpl::variable<bool> sendUploadProgressReactive;
rpl::variable<bool> sendOfflinePacketAfterOnlineReactive;
rpl::variable<QString> deletedMarkReactive;
rpl::variable<QString> editedMarkReactive;
rpl::variable<int> showPeerIdReactive;
rpl::variable<bool> ghostModeEnabled;
rpl::lifetime lifetime = rpl::lifetime();
bool ghostModeEnabled_util(AyuGramSettings &settingsUtil)
{
return
!settingsUtil.sendReadMessages
&& !settingsUtil.sendReadStories
&& !settingsUtil.sendOnlinePackets
&& !settingsUtil.sendUploadProgress
&& settingsUtil.sendOfflinePacketAfterOnline;
}
void initialize()
{
if (settings.has_value())
{
return;
}
settings = AyuGramSettings();
sendReadMessagesReactive.value() | rpl::filter([=](bool val)
{
return (val != settings->sendReadMessages);
}) | start_with_next([=](bool val)
{
ghostModeEnabled = ghostModeEnabled_util(settings.value());
}, lifetime);
// ..
sendReadStoriesReactive.value() | rpl::filter([=](bool val)
{
return (val != settings->sendReadStories);
}) | start_with_next([=](bool val)
{
ghostModeEnabled = ghostModeEnabled_util(settings.value());
}, lifetime);
// ..
sendOnlinePacketsReactive.value() | rpl::filter([=](bool val)
{
return (val != settings->sendOnlinePackets);
}) | start_with_next([=](bool val)
{
ghostModeEnabled = ghostModeEnabled_util(settings.value());
}, lifetime);
// ..
sendUploadProgressReactive.value() | rpl::filter([=](bool val)
{
return (val != settings->sendUploadProgress);
}) | start_with_next([=](bool val)
{
ghostModeEnabled = ghostModeEnabled_util(settings.value());
}, lifetime);
// ..
sendOfflinePacketAfterOnlineReactive.value() | rpl::filter([=](bool val)
{
return (val != settings->sendOfflinePacketAfterOnline);
}) | start_with_next([=](bool val)
{
ghostModeEnabled = ghostModeEnabled_util(settings.value());
}, lifetime);
}
void postinitialize()
{
sendReadMessagesReactive = settings->sendReadMessages;
sendReadStoriesReactive = settings->sendReadStories;
sendUploadProgressReactive = settings->sendUploadProgress;
sendOfflinePacketAfterOnlineReactive = settings->sendOfflinePacketAfterOnline;
sendOnlinePacketsReactive = settings->sendOnlinePackets;
deletedMarkReactive = settings->deletedMark;
editedMarkReactive = settings->editedMark;
showPeerIdReactive = settings->showPeerId;
ghostModeEnabled = ghostModeEnabled_util(settings.value());
}
AyuGramSettings& getInstance()
{
initialize();
return settings.value();
}
void load()
{
QFile file(filename);
if (!file.exists())
{
return;
}
file.open(QIODevice::ReadOnly);
QByteArray data = file.readAll();
file.close();
initialize();
json p = json::parse(data);
try
{
settings = p.get<AyuGramSettings>();
}
catch (...)
{
LOG(("AyuGramSettings: failed to parse settings file"));
}
postinitialize();
}
void save()
{
initialize();
json p = settings.value();
QFile file(filename);
file.open(QIODevice::WriteOnly);
file.write(p.dump().c_str());
file.close();
postinitialize();
}
void AyuGramSettings::set_sendReadMessages(bool val)
{
sendReadMessages = val;
sendReadMessagesReactive = val;
}
void AyuGramSettings::set_sendReadStories(bool val)
{
sendReadStories = val;
sendReadStoriesReactive = val;
}
void AyuGramSettings::set_sendOnlinePackets(bool val)
{
sendOnlinePackets = val;
sendOnlinePacketsReactive = val;
}
void AyuGramSettings::set_sendUploadProgress(bool val)
{
sendUploadProgress = val;
sendUploadProgressReactive = val;
}
void AyuGramSettings::set_sendOfflinePacketAfterOnline(bool val)
{
sendOfflinePacketAfterOnline = val;
sendOfflinePacketAfterOnlineReactive = val;
}
void AyuGramSettings::set_ghostModeEnabled(bool val)
{
set_sendReadMessages(!val);
set_sendReadStories(!val);
set_sendOnlinePackets(!val);
set_sendUploadProgress(!val);
set_sendOfflinePacketAfterOnline(val);
}
void AyuGramSettings::set_markReadAfterSend(bool val)
{
markReadAfterSend = val;
}
void AyuGramSettings::set_useScheduledMessages(bool val)
{
useScheduledMessages = val;
}
void AyuGramSettings::set_keepDeletedMessages(bool val)
{
saveDeletedMessages = val;
}
void AyuGramSettings::set_keepMessagesHistory(bool val)
{
saveMessagesHistory = val;
}
void AyuGramSettings::set_disableAds(bool val)
{
disableAds = val;
}
void AyuGramSettings::set_disableStories(bool val)
{
disableStories = val;
}
void AyuGramSettings::set_localPremium(bool val)
{
localPremium = val;
}
void AyuGramSettings::set_copyUsernameAsLink(bool val)
{
copyUsernameAsLink = val;
}
void AyuGramSettings::set_appIcon(QString val)
{
appIcon = std::move(val);
}
void AyuGramSettings::set_deletedMark(QString val)
{
deletedMark = std::move(val);
deletedMarkReactive = deletedMark;
}
void AyuGramSettings::set_editedMark(QString val)
{
editedMark = std::move(val);
editedMarkReactive = editedMark;
}
void AyuGramSettings::set_recentStickersCount(int val)
{
recentStickersCount = val;
}
void AyuGramSettings::set_showGhostToggleInDrawer(bool val)
{
showGhostToggleInDrawer = val;
}
void AyuGramSettings::set_showPeerId(int val)
{
showPeerId = val;
showPeerIdReactive = val;
}
void AyuGramSettings::set_showMessageSeconds(bool val)
{
showMessageSeconds = val;
}
void AyuGramSettings::set_hideAllChatsFolder(bool val)
{
hideAllChatsFolder = val;
}
void AyuGramSettings::set_stickerConfirmation(bool val)
{
stickerConfirmation = val;
}
void AyuGramSettings::set_gifConfirmation(bool val)
{
gifConfirmation = val;
}
void AyuGramSettings::set_voiceConfirmation(bool val)
{
voiceConfirmation = val;
}
bool get_ghostModeEnabled()
{
return ghostModeEnabled.current();
}
rpl::producer<QString> get_deletedMarkReactive()
{
return deletedMarkReactive.value();
}
rpl::producer<QString> get_editedMarkReactive()
{
return editedMarkReactive.value();
}
rpl::producer<int> get_showPeerIdReactive()
{
return showPeerIdReactive.value();
}
rpl::producer<bool> get_ghostModeEnabledReactive()
{
return ghostModeEnabled.value();
}
}
void initialize()
{
if (settings.has_value()) {
return;
}
settings = AyuGramSettings();
sendReadMessagesReactive.value() | rpl::filter([=](bool val)
{
return (val != settings->sendReadMessages);
}) | start_with_next([=](bool val)
{
ghostModeEnabled =
ghostModeEnabled_util(settings.value());
}, lifetime);
// ..
sendReadStoriesReactive.value() | rpl::filter([=](bool val)
{
return (val != settings->sendReadStories);
}) | start_with_next([=](bool val)
{
ghostModeEnabled =
ghostModeEnabled_util(settings.value());
}, lifetime);
// ..
sendOnlinePacketsReactive.value() | rpl::filter([=](bool val)
{
return (val != settings->sendOnlinePackets);
}) | start_with_next([=](bool val)
{
ghostModeEnabled =
ghostModeEnabled_util(settings
.value());
}, lifetime);
// ..
sendUploadProgressReactive.value() | rpl::filter([=](bool val)
{
return (val != settings->sendUploadProgress);
}) | start_with_next([=](bool val)
{
ghostModeEnabled =
ghostModeEnabled_util(settings
.value());
}, lifetime);
// ..
sendOfflinePacketAfterOnlineReactive.value() | rpl::filter([=](bool val)
{
return (val
!= settings->sendOfflinePacketAfterOnline);
}) | start_with_next([=](bool val)
{
ghostModeEnabled =
ghostModeEnabled_util(
settings.value());
}, lifetime);
}
void postinitialize()
{
sendReadMessagesReactive = settings->sendReadMessages;
sendReadStoriesReactive = settings->sendReadStories;
sendUploadProgressReactive = settings->sendUploadProgress;
sendOfflinePacketAfterOnlineReactive = settings->sendOfflinePacketAfterOnline;
sendOnlinePacketsReactive = settings->sendOnlinePackets;
deletedMarkReactive = settings->deletedMark;
editedMarkReactive = settings->editedMark;
showPeerIdReactive = settings->showPeerId;
ghostModeEnabled = ghostModeEnabled_util(settings.value());
}
AyuGramSettings &getInstance()
{
initialize();
return settings.value();
}
void load()
{
QFile file(filename);
if (!file.exists()) {
return;
}
file.open(QIODevice::ReadOnly);
QByteArray data = file.readAll();
file.close();
initialize();
json p = json::parse(data);
try {
settings = p.get<AyuGramSettings>();
}
catch (...) {
LOG(("AyuGramSettings: failed to parse settings file"));
}
postinitialize();
}
void save()
{
initialize();
json p = settings.value();
QFile file(filename);
file.open(QIODevice::WriteOnly);
file.write(p.dump().c_str());
file.close();
postinitialize();
}
void AyuGramSettings::set_sendReadMessages(bool val)
{
sendReadMessages = val;
sendReadMessagesReactive = val;
}
void AyuGramSettings::set_sendReadStories(bool val)
{
sendReadStories = val;
sendReadStoriesReactive = val;
}
void AyuGramSettings::set_sendOnlinePackets(bool val)
{
sendOnlinePackets = val;
sendOnlinePacketsReactive = val;
}
void AyuGramSettings::set_sendUploadProgress(bool val)
{
sendUploadProgress = val;
sendUploadProgressReactive = val;
}
void AyuGramSettings::set_sendOfflinePacketAfterOnline(bool val)
{
sendOfflinePacketAfterOnline = val;
sendOfflinePacketAfterOnlineReactive = val;
}
void AyuGramSettings::set_ghostModeEnabled(bool val)
{
set_sendReadMessages(!val);
set_sendReadStories(!val);
set_sendOnlinePackets(!val);
set_sendUploadProgress(!val);
set_sendOfflinePacketAfterOnline(val);
}
void AyuGramSettings::set_markReadAfterSend(bool val)
{
markReadAfterSend = val;
}
void AyuGramSettings::set_useScheduledMessages(bool val)
{
useScheduledMessages = val;
}
void AyuGramSettings::set_keepDeletedMessages(bool val)
{
saveDeletedMessages = val;
}
void AyuGramSettings::set_keepMessagesHistory(bool val)
{
saveMessagesHistory = val;
}
void AyuGramSettings::set_disableAds(bool val)
{
disableAds = val;
}
void AyuGramSettings::set_disableStories(bool val)
{
disableStories = val;
}
void AyuGramSettings::set_localPremium(bool val)
{
localPremium = val;
}
void AyuGramSettings::set_copyUsernameAsLink(bool val)
{
copyUsernameAsLink = val;
}
void AyuGramSettings::set_appIcon(QString val)
{
appIcon = std::move(val);
}
void AyuGramSettings::set_deletedMark(QString val)
{
deletedMark = std::move(val);
deletedMarkReactive = deletedMark;
}
void AyuGramSettings::set_editedMark(QString val)
{
editedMark = std::move(val);
editedMarkReactive = editedMark;
}
void AyuGramSettings::set_recentStickersCount(int val)
{
recentStickersCount = val;
}
void AyuGramSettings::set_showGhostToggleInDrawer(bool val)
{
showGhostToggleInDrawer = val;
}
void AyuGramSettings::set_showPeerId(int val)
{
showPeerId = val;
showPeerIdReactive = val;
}
void AyuGramSettings::set_showMessageSeconds(bool val)
{
showMessageSeconds = val;
}
void AyuGramSettings::set_hideAllChatsFolder(bool val)
{
hideAllChatsFolder = val;
}
void AyuGramSettings::set_stickerConfirmation(bool val)
{
stickerConfirmation = val;
}
void AyuGramSettings::set_gifConfirmation(bool val)
{
gifConfirmation = val;
}
void AyuGramSettings::set_voiceConfirmation(bool val)
{
voiceConfirmation = val;
}
bool get_ghostModeEnabled()
{
return ghostModeEnabled.current();
}
rpl::producer<QString> get_deletedMarkReactive()
{
return deletedMarkReactive.value();
}
rpl::producer<QString> get_editedMarkReactive()
{
return editedMarkReactive.value();
}
rpl::producer<int> get_showPeerIdReactive()
{
return showPeerIdReactive.value();
}
rpl::producer<bool> get_ghostModeEnabledReactive()
{
return ghostModeEnabled.value();
}
}

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "lang_auto.h"
@ -14,176 +13,180 @@
namespace AyuSettings
{
const auto DEFAULT_ICON = QString("default");
const auto ALT_ICON = QString("alt");
const auto NOTHING_ICON = QString("nothing");
class AyuGramSettings
const auto DEFAULT_ICON = QString("default");
const auto ALT_ICON = QString("alt");
const auto NOTHING_ICON = QString("nothing");
class AyuGramSettings
{
public:
AyuGramSettings()
{
public:
AyuGramSettings()
{
// ~ Ghost essentials
sendReadMessages = true;
sendReadStories = true;
sendOnlinePackets = true;
sendUploadProgress = true;
sendOfflinePacketAfterOnline = false;
// ~ Ghost essentials
sendReadMessages = true;
sendReadStories = true;
sendOnlinePackets = true;
sendUploadProgress = true;
sendOfflinePacketAfterOnline = false;
markReadAfterSend = true;
useScheduledMessages = false;
markReadAfterSend = true;
useScheduledMessages = false;
// ~ Message edits & deletion history
saveDeletedMessages = true;
saveMessagesHistory = true;
// ~ Message edits & deletion history
saveDeletedMessages = true;
saveMessagesHistory = true;
// ~ QoL toggles
disableAds = true;
disableStories = false;
localPremium = false;
copyUsernameAsLink = true;
// ~ QoL toggles
disableAds = true;
disableStories = false;
localPremium = false;
copyUsernameAsLink = true;
// ~ Customization
appIcon = DEFAULT_ICON;
deletedMark = "🧹";
editedMark = tr::lng_edited(tr::now);
recentStickersCount = 20;
showGhostToggleInDrawer = true;
// ~ Customization
appIcon = DEFAULT_ICON;
deletedMark = "🧹";
editedMark = tr::lng_edited(tr::now);
recentStickersCount = 20;
showGhostToggleInDrawer = true;
/*
* showPeerId = 0 means no ID shown
* showPeerId = 1 means ID shown as for Telegram API devs
* showPeerId = 2 means ID shown as for Bot API devs (-100)
*/
showPeerId = 2;
/*
* showPeerId = 0 means no ID shown
* showPeerId = 1 means ID shown as for Telegram API devs
* showPeerId = 2 means ID shown as for Bot API devs (-100)
*/
showPeerId = 2;
hideAllChatsFolder = false;
showMessageSeconds = false;
hideAllChatsFolder = false;
showMessageSeconds = false;
// ~ Confirmations
stickerConfirmation = false;
gifConfirmation = false;
voiceConfirmation = false;
}
// ~ Confirmations
stickerConfirmation = false;
gifConfirmation = false;
voiceConfirmation = false;
}
bool sendReadMessages;
bool sendReadStories;
bool sendOnlinePackets;
bool sendUploadProgress;
bool sendOfflinePacketAfterOnline;
bool markReadAfterSend;
bool useScheduledMessages;
bool saveDeletedMessages;
bool saveMessagesHistory;
bool disableAds;
bool disableStories;
bool localPremium;
bool copyUsernameAsLink;
QString appIcon;
QString deletedMark;
QString editedMark;
int recentStickersCount;
bool showGhostToggleInDrawer;
int showPeerId;
bool hideAllChatsFolder;
bool showMessageSeconds;
bool stickerConfirmation;
bool gifConfirmation;
bool voiceConfirmation;
bool sendReadMessages;
bool sendReadStories;
bool sendOnlinePackets;
bool sendUploadProgress;
bool sendOfflinePacketAfterOnline;
bool markReadAfterSend;
bool useScheduledMessages;
bool saveDeletedMessages;
bool saveMessagesHistory;
bool disableAds;
bool disableStories;
bool localPremium;
bool copyUsernameAsLink;
QString appIcon;
QString deletedMark;
QString editedMark;
int recentStickersCount;
bool showGhostToggleInDrawer;
int showPeerId;
bool hideAllChatsFolder;
bool showMessageSeconds;
bool stickerConfirmation;
bool gifConfirmation;
bool voiceConfirmation;
public:
void set_sendReadMessages(bool val);
public:
void set_sendReadMessages(bool val);
void set_sendReadStories(bool val);
void set_sendReadStories(bool val);
void set_sendOnlinePackets(bool val);
void set_sendOnlinePackets(bool val);
void set_sendUploadProgress(bool val);
void set_sendUploadProgress(bool val);
void set_sendOfflinePacketAfterOnline(bool val);
void set_sendOfflinePacketAfterOnline(bool val);
void set_ghostModeEnabled(bool val);
void set_ghostModeEnabled(bool val);
void set_markReadAfterSend(bool val);
void set_markReadAfterSend(bool val);
void set_useScheduledMessages(bool val);
void set_useScheduledMessages(bool val);
void set_keepDeletedMessages(bool val);
void set_keepDeletedMessages(bool val);
void set_keepMessagesHistory(bool val);
void set_keepMessagesHistory(bool val);
void set_disableAds(bool val);
void set_disableAds(bool val);
void set_disableStories(bool val);
void set_disableStories(bool val);
void set_localPremium(bool val);
void set_localPremium(bool val);
void set_copyUsernameAsLink(bool val);
void set_copyUsernameAsLink(bool val);
void set_appIcon(QString val);
void set_appIcon(QString val);
void set_deletedMark(QString val);
void set_deletedMark(QString val);
void set_editedMark(QString val);
void set_editedMark(QString val);
void set_recentStickersCount(int val);
void set_recentStickersCount(int val);
void set_showGhostToggleInDrawer(bool val);
void set_showGhostToggleInDrawer(bool val);
void set_showPeerId(int val);
void set_showPeerId(int val);
void set_showMessageSeconds(bool val);
void set_showMessageSeconds(bool val);
void set_hideAllChatsFolder(bool val);
void set_hideAllChatsFolder(bool val);
void set_stickerConfirmation(bool val);
void set_stickerConfirmation(bool val);
void set_gifConfirmation(bool val);
void set_gifConfirmation(bool val);
void set_voiceConfirmation(bool val);
};
void set_voiceConfirmation(bool val);
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
AyuGramSettings,
sendReadMessages,
sendReadStories,
sendOnlinePackets,
sendUploadProgress,
sendOfflinePacketAfterOnline,
markReadAfterSend,
useScheduledMessages,
saveDeletedMessages,
saveMessagesHistory,
disableAds,
disableStories,
localPremium,
copyUsernameAsLink,
appIcon,
deletedMark,
editedMark,
recentStickersCount,
showGhostToggleInDrawer,
showPeerId,
showMessageSeconds,
hideAllChatsFolder,
stickerConfirmation,
gifConfirmation,
voiceConfirmation
);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
AyuGramSettings,
sendReadMessages,
sendReadStories,
sendOnlinePackets,
sendUploadProgress,
sendOfflinePacketAfterOnline,
markReadAfterSend,
useScheduledMessages,
saveDeletedMessages,
saveMessagesHistory,
disableAds,
disableStories,
localPremium,
copyUsernameAsLink,
appIcon,
deletedMark,
editedMark,
recentStickersCount,
showGhostToggleInDrawer,
showPeerId,
showMessageSeconds,
hideAllChatsFolder,
stickerConfirmation,
gifConfirmation,
voiceConfirmation
);
AyuGramSettings& getInstance();
AyuGramSettings &getInstance();
void load();
void load();
void save();
void save();
rpl::producer<QString> get_deletedMarkReactive();
rpl::producer<QString> get_deletedMarkReactive();
rpl::producer<QString> get_editedMarkReactive();
rpl::producer<QString> get_editedMarkReactive();
rpl::producer<int> get_showPeerIdReactive();
rpl::producer<int> get_showPeerIdReactive();
bool get_ghostModeEnabled();
bool get_ghostModeEnabled();
rpl::producer<bool> get_ghostModeEnabledReactive();
rpl::producer<bool> get_ghostModeEnabledReactive();
}

View file

@ -9,15 +9,17 @@
namespace AyuState
{
void setAllowSendReadPacket(bool val, int resetAfter)
{
allowSendReadPacket.val = val;
allowSendReadPacket.resetAfter = resetAfter;
}
bool getAllowSendPacket()
{
auto settings = &AyuSettings::getInstance();
return settings->sendReadMessages || processVariable(allowSendReadPacket);
}
void setAllowSendReadPacket(bool val, int resetAfter)
{
allowSendReadPacket.val = val;
allowSendReadPacket.resetAfter = resetAfter;
}
bool getAllowSendPacket()
{
auto settings = &AyuSettings::getInstance();
return settings->sendReadMessages || processVariable(allowSendReadPacket);
}
}

View file

@ -4,44 +4,45 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "ayu_settings.h"
namespace AyuState
{
namespace
{
class AyuStateVariable
{
public:
bool val;
int resetAfter;
};
AyuStateVariable allowSendReadPacket;
namespace
{
bool processVariable(AyuStateVariable& variable)
{
if (variable.resetAfter == -1)
{
return variable.val;
}
class AyuStateVariable
{
public:
bool val;
int resetAfter;
};
variable.resetAfter -= 1;
auto val = variable.val;
AyuStateVariable allowSendReadPacket;
if (variable.resetAfter == 0)
{
variable.val = false;
}
return val;
}
bool processVariable(AyuStateVariable &variable)
{
if (variable.resetAfter == -1) {
return variable.val;
}
void setAllowSendReadPacket(bool val, int resetAfter = 1);
variable.resetAfter -= 1;
auto val = variable.val;
if (variable.resetAfter == 0) {
variable.val = false;
}
return val;
}
}
void setAllowSendReadPacket(bool val, int resetAfter = 1);
bool getAllowSendPacket();
bool getAllowSendPacket();
}

View file

@ -9,102 +9,127 @@
#include "entities.h"
#include "ayu/libs/sqlite/sqlite_orm.h"
#include "ayu/utils/telegram_helpers.h"
using namespace sqlite_orm;
auto storage = make_storage(
"ayugram.db",
make_table(
"editedmessage",
make_column("userId", &EditedMessage::get_user_id, &EditedMessage::set_user_id),
make_column("dialogId", &EditedMessage::get_dialog_id, &EditedMessage::set_dialog_id),
make_column("groupedId", &EditedMessage::get_grouped_id, &EditedMessage::set_grouped_id),
make_column("peerId", &EditedMessage::get_peer_id, &EditedMessage::set_peer_id),
make_column("fromId", &EditedMessage::get_from_id, &EditedMessage::set_from_id),
make_column("topicId", &EditedMessage::get_topic_id, &EditedMessage::set_topic_id),
make_column("messageId", &EditedMessage::get_message_id, &EditedMessage::set_message_id),
make_column("date", &EditedMessage::get_date, &EditedMessage::set_date),
make_column("flags", &EditedMessage::get_flags, &EditedMessage::set_flags),
make_column("editDate", &EditedMessage::get_edit_date, &EditedMessage::set_edit_date),
make_column("editHide", &EditedMessage::is_edit_hide, &EditedMessage::set_edit_hide),
make_column("out", &EditedMessage::is_out, &EditedMessage::set_out),
make_column("entityCreateDate", &EditedMessage::get_entity_create_date, &EditedMessage::set_entity_create_date),
make_column("text", &EditedMessage::get_text, &EditedMessage::set_text),
make_column("textEntities", &EditedMessage::get_text_entities, &EditedMessage::set_text_entities),
make_column("mediaPath", &EditedMessage::get_media_path, &EditedMessage::set_media_path),
make_column("documentType", &EditedMessage::get_document_type, &EditedMessage::set_document_type),
make_column("documentSerialized", &EditedMessage::get_document_serialized,
&EditedMessage::set_document_serialized),
make_column("thumbsSerialized", &EditedMessage::get_thumbs_serialized, &EditedMessage::set_thumbs_serialized),
make_column("documentAttributesSerialized", &EditedMessage::get_document_attributes_serialized,
&EditedMessage::set_document_attributes_serialized),
make_column("mimeType", &EditedMessage::get_mime_type, &EditedMessage::set_mime_type)
),
make_table(
"deletedmessage",
make_column("userId", &DeletedMessage::get_user_id, &DeletedMessage::set_user_id),
make_column("dialogId", &DeletedMessage::get_dialog_id, &DeletedMessage::set_dialog_id),
make_column("groupedId", &DeletedMessage::get_grouped_id, &DeletedMessage::set_grouped_id),
make_column("peerId", &DeletedMessage::get_peer_id, &DeletedMessage::set_peer_id),
make_column("fromId", &DeletedMessage::get_from_id, &DeletedMessage::set_from_id),
make_column("topicId", &DeletedMessage::get_topic_id, &DeletedMessage::set_topic_id),
make_column("messageId", &DeletedMessage::get_message_id, &DeletedMessage::set_message_id),
make_column("date", &DeletedMessage::get_date, &DeletedMessage::set_date),
make_column("flags", &DeletedMessage::get_flags, &DeletedMessage::set_flags),
make_column("editDate", &DeletedMessage::get_edit_date, &DeletedMessage::set_edit_date),
make_column("editHide", &DeletedMessage::is_edit_hide, &DeletedMessage::set_edit_hide),
make_column("out", &DeletedMessage::is_out, &DeletedMessage::set_out),
make_column("entityCreateDate", &DeletedMessage::get_entity_create_date,
&DeletedMessage::set_entity_create_date),
make_column("text", &DeletedMessage::get_text, &DeletedMessage::set_text),
make_column("textEntities", &DeletedMessage::get_text_entities, &DeletedMessage::set_text_entities),
make_column("mediaPath", &DeletedMessage::get_media_path, &DeletedMessage::set_media_path),
make_column("documentType", &DeletedMessage::get_document_type, &DeletedMessage::set_document_type),
make_column("documentSerialized", &DeletedMessage::get_document_serialized,
&DeletedMessage::set_document_serialized),
make_column("thumbsSerialized", &DeletedMessage::get_thumbs_serialized, &DeletedMessage::set_thumbs_serialized),
make_column("documentAttributesSerialized", &DeletedMessage::get_document_attributes_serialized,
&DeletedMessage::set_document_attributes_serialized),
make_column("mimeType", &DeletedMessage::get_mime_type, &DeletedMessage::set_mime_type)
)
auto storage = make_storage("ayugram.db",
make_table("DeletedMessage",
make_column("userId", &DeletedMessage::userId),
make_column("dialogId", &DeletedMessage::dialogId),
make_column("groupedId", &DeletedMessage::groupedId),
make_column("peerId", &DeletedMessage::peerId),
make_column("fromId", &DeletedMessage::fromId),
make_column("topicId", &DeletedMessage::topicId),
make_column("messageId", &DeletedMessage::messageId),
make_column("date", &DeletedMessage::date),
make_column("flags", &DeletedMessage::flags),
make_column("editDate", &DeletedMessage::editDate),
make_column("views", &DeletedMessage::views),
make_column("fwdFlags", &DeletedMessage::fwdFlags),
make_column("fwdFromId", &DeletedMessage::fwdFromId),
make_column("fwdName", &DeletedMessage::fwdName),
make_column("fwdDate", &DeletedMessage::fwdDate),
make_column("fwdPostAuthor", &DeletedMessage::fwdPostAuthor),
make_column("replyFlags", &DeletedMessage::replyFlags),
make_column("replyMessageId", &DeletedMessage::replyMessageId),
make_column("replyPeerId", &DeletedMessage::replyPeerId),
make_column("replyTopId", &DeletedMessage::replyTopId),
make_column("replyForumTopic", &DeletedMessage::replyForumTopic),
make_column("entityCreateDate", &DeletedMessage::entityCreateDate),
make_column("text", &DeletedMessage::text),
make_column("textEntities", &DeletedMessage::textEntities),
make_column("mediaPath", &DeletedMessage::mediaPath),
make_column("hqThumbPath", &DeletedMessage::hqThumbPath),
make_column("documentType", &DeletedMessage::documentType),
make_column("documentSerialized", &DeletedMessage::documentSerialized),
make_column("thumbsSerialized", &DeletedMessage::thumbsSerialized),
make_column("documentAttributesSerialized",
&DeletedMessage::documentAttributesSerialized),
make_column("mimeType", &DeletedMessage::mimeType)
),
make_table("EditedMessage",
make_column("userId", &EditedMessage::userId),
make_column("dialogId", &EditedMessage::dialogId),
make_column("groupedId", &EditedMessage::groupedId),
make_column("peerId", &EditedMessage::peerId),
make_column("fromId", &EditedMessage::fromId),
make_column("topicId", &EditedMessage::topicId),
make_column("messageId", &EditedMessage::messageId),
make_column("date", &EditedMessage::date),
make_column("flags", &EditedMessage::flags),
make_column("editDate", &EditedMessage::editDate),
make_column("views", &EditedMessage::views),
make_column("fwdFlags", &EditedMessage::fwdFlags),
make_column("fwdFromId", &EditedMessage::fwdFromId),
make_column("fwdName", &EditedMessage::fwdName),
make_column("fwdDate", &EditedMessage::fwdDate),
make_column("fwdPostAuthor", &EditedMessage::fwdPostAuthor),
make_column("replyFlags", &EditedMessage::replyFlags),
make_column("replyMessageId", &EditedMessage::replyMessageId),
make_column("replyPeerId", &EditedMessage::replyPeerId),
make_column("replyTopId", &EditedMessage::replyTopId),
make_column("replyForumTopic", &EditedMessage::replyForumTopic),
make_column("entityCreateDate", &EditedMessage::entityCreateDate),
make_column("text", &EditedMessage::text),
make_column("textEntities", &EditedMessage::textEntities),
make_column("mediaPath", &EditedMessage::mediaPath),
make_column("hqThumbPath", &EditedMessage::hqThumbPath),
make_column("documentType", &EditedMessage::documentType),
make_column("documentSerialized", &EditedMessage::documentSerialized),
make_column("thumbsSerialized", &EditedMessage::thumbsSerialized),
make_column("documentAttributesSerialized",
&EditedMessage::documentAttributesSerialized),
make_column("mimeType", &EditedMessage::mimeType)
),
make_table("DeletedDialog",
make_column("userId", &DeletedDialog::userId),
make_column("dialogId", &DeletedDialog::dialogId),
make_column("peerId", &DeletedDialog::peerId),
make_column("topMessage", &DeletedDialog::topMessage),
make_column("lastMessageDate", &DeletedDialog::lastMessageDate),
make_column("flags", &DeletedDialog::flags),
make_column("entityCreateDate", &DeletedDialog::entityCreateDate)
)
);
namespace AyuDatabase
{
void initialize()
{
storage.sync_schema();
storage.begin_transaction();
storage.commit();
}
void initialize()
{
storage.sync_schema();
storage.begin_transaction();
storage.commit();
}
void addEditedMessage(const EditedMessage &message)
{
storage.begin_transaction();
storage.insert(message);
storage.commit();
}
std::vector<EditedMessage> getEditedMessages(ID userId, ID dialogId, ID messageId)
{
return storage.get_all<EditedMessage>(
where(
c(&EditedMessage::userId) == userId and
c(&EditedMessage::dialogId) == dialogId and
c(&EditedMessage::messageId) == messageId
)
);
}
bool hasRevisions(ID userId, ID dialogId, ID messageId)
{
return storage.count<EditedMessage>(
where(
c(&EditedMessage::userId) == userId and
c(&EditedMessage::dialogId) == dialogId and
c(&EditedMessage::messageId) == messageId
)
) > 0;
}
void addEditedMessage(const EditedMessage& message)
{
storage.begin_transaction();
storage.insert(message);
storage.commit();
}
std::vector<EditedMessage> getEditedMessages(ID userId, ID dialogId, ID messageId)
{
return storage.get_all<EditedMessage>(
where(
c(&EditedMessage::get_user_id) == userId and
c(&EditedMessage::get_dialog_id) == dialogId and
c(&EditedMessage::get_message_id) == messageId
)
);
}
bool hasRevisions(ID userId, ID dialogId, ID messageId)
{
return storage.count<EditedMessage>(
where(
c(&EditedMessage::get_user_id) == userId and
c(&EditedMessage::get_dialog_id) == dialogId and
c(&EditedMessage::get_message_id) == messageId
)
) > 0;
}
}

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "entities.h"
@ -13,9 +12,11 @@
namespace AyuDatabase
{
void initialize();
void addEditedMessage(const EditedMessage& message);
std::vector<EditedMessage> getEditedMessages(ID userId, ID dialogId, ID messageId);
bool hasRevisions(ID userId, ID dialogId, ID messageId);
void initialize();
void addEditedMessage(const EditedMessage &message);
std::vector<EditedMessage> getEditedMessages(ID userId, ID dialogId, ID messageId);
bool hasRevisions(ID userId, ID dialogId, ID messageId);
}

View file

@ -4,18 +4,17 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include <string>
#define ID long long
// https://github.com/AyuGram/AyuGram4A/blob/rewrite/TMessagesProj/src/main/java/com/radolyn/ayugram/database/entities/AyuMessageBase.java
template<typename TableName>
class AyuMessageBase
{
public:
ID fakeId;
ID userId;
ID dialogId;
ID groupedId;
@ -24,449 +23,43 @@ public:
ID topicId;
int messageId;
int date;
int flags;
int editDate;
bool editHide;
bool out;
int views;
int fwdFlags;
ID fwdFromId;
std::string fwdName;
int fwdDate;
std::string fwdPostAuthor;
int replyFlags;
int replyMessageId;
ID replyPeerId;
int replyTopId;
bool replyForumTopic;
int entityCreateDate;
std::string text; // plain text
std::string textEntities; // TL serialized
std::string mediaPath; // full path
int documentType; // see DOCUMENT_TYPE_*
std::string documentSerialized; // for sticker; TL serialized
std::string thumbsSerialized; // for video/etc.; TL serialized
std::string documentAttributesSerialized; // for video/voice/etc.; TL serialized
std::string text;
std::vector<char> textEntities;
std::string mediaPath;
std::string hqThumbPath;
int documentType;
std::vector<char> documentSerialized;
std::vector<char> thumbsSerialized;
std::vector<char> documentAttributesSerialized;
std::string mimeType;
};
class DeletedMessage : public AyuMessageBase
using DeletedMessage = AyuMessageBase<struct DeletedMessageTag>;
using EditedMessage = AyuMessageBase<struct EditedMessageTag>;
class DeletedDialog
{
public:
[[nodiscard]] long long get_user_id() const
{
return userId;
}
void set_user_id(long long user_id)
{
userId = user_id;
}
[[nodiscard]] long long get_dialog_id() const
{
return dialogId;
}
void set_dialog_id(long long dialog_id)
{
dialogId = dialog_id;
}
[[nodiscard]] long long get_grouped_id() const
{
return groupedId;
}
void set_grouped_id(long long grouped_id)
{
groupedId = grouped_id;
}
[[nodiscard]] long long get_peer_id() const
{
return peerId;
}
void set_peer_id(long long peer_id)
{
peerId = peer_id;
}
[[nodiscard]] long long get_from_id() const
{
return fromId;
}
void set_from_id(long long from_id)
{
fromId = from_id;
}
[[nodiscard]] long long get_topic_id() const
{
return topicId;
}
void set_topic_id(long long topic_id)
{
topicId = topic_id;
}
[[nodiscard]] int get_message_id() const
{
return messageId;
}
void set_message_id(int message_id)
{
messageId = message_id;
}
[[nodiscard]] int get_date() const
{
return date;
}
void set_date(int date)
{
this->date = date;
}
[[nodiscard]] int get_flags() const
{
return flags;
}
void set_flags(int flags)
{
this->flags = flags;
}
[[nodiscard]] int get_edit_date() const
{
return editDate;
}
void set_edit_date(int edit_date)
{
editDate = edit_date;
}
[[nodiscard]] bool is_edit_hide() const
{
return editHide;
}
void set_edit_hide(bool edit_hide)
{
editHide = edit_hide;
}
[[nodiscard]] bool is_out() const
{
return out;
}
void set_out(bool out)
{
this->out = out;
}
[[nodiscard]] int get_entity_create_date() const
{
return entityCreateDate;
}
void set_entity_create_date(int entity_create_date)
{
entityCreateDate = entity_create_date;
}
[[nodiscard]] std::string get_text() const
{
return text;
}
void set_text(const std::string& text)
{
this->text = text;
}
[[nodiscard]] std::string get_text_entities() const
{
return textEntities;
}
void set_text_entities(const std::string& text_entities)
{
textEntities = text_entities;
}
[[nodiscard]] std::string get_media_path() const
{
return mediaPath;
}
void set_media_path(const std::string& media_path)
{
mediaPath = media_path;
}
[[nodiscard]] int get_document_type() const
{
return documentType;
}
void set_document_type(int document_type)
{
documentType = document_type;
}
[[nodiscard]] std::string get_document_serialized() const
{
return documentSerialized;
}
void set_document_serialized(const std::string& document_serialized)
{
documentSerialized = document_serialized;
}
[[nodiscard]] std::string get_thumbs_serialized() const
{
return thumbsSerialized;
}
void set_thumbs_serialized(const std::string& thumbs_serialized)
{
thumbsSerialized = thumbs_serialized;
}
[[nodiscard]] std::string get_document_attributes_serialized() const
{
return documentAttributesSerialized;
}
void set_document_attributes_serialized(const std::string& document_attributes_serialized)
{
documentAttributesSerialized = document_attributes_serialized;
}
[[nodiscard]] std::string get_mime_type() const
{
return mimeType;
}
void set_mime_type(const std::string& mime_type)
{
mimeType = mime_type;
}
};
class EditedMessage : public AyuMessageBase
{
public:
[[nodiscard]] long long get_user_id() const
{
return userId;
}
void set_user_id(long long user_id)
{
userId = user_id;
}
[[nodiscard]] long long get_dialog_id() const
{
return dialogId;
}
void set_dialog_id(long long dialog_id)
{
dialogId = dialog_id;
}
[[nodiscard]] long long get_grouped_id() const
{
return groupedId;
}
void set_grouped_id(long long grouped_id)
{
groupedId = grouped_id;
}
[[nodiscard]] long long get_peer_id() const
{
return peerId;
}
void set_peer_id(long long peer_id)
{
peerId = peer_id;
}
[[nodiscard]] long long get_from_id() const
{
return fromId;
}
void set_from_id(long long from_id)
{
fromId = from_id;
}
[[nodiscard]] long long get_topic_id() const
{
return topicId;
}
void set_topic_id(long long topic_id)
{
topicId = topic_id;
}
[[nodiscard]] int get_message_id() const
{
return messageId;
}
void set_message_id(int message_id)
{
messageId = message_id;
}
[[nodiscard]] int get_date() const
{
return date;
}
void set_date(int date)
{
this->date = date;
}
[[nodiscard]] int get_flags() const
{
return flags;
}
void set_flags(int flags)
{
this->flags = flags;
}
[[nodiscard]] int get_edit_date() const
{
return editDate;
}
void set_edit_date(int edit_date)
{
editDate = edit_date;
}
[[nodiscard]] bool is_edit_hide() const
{
return editHide;
}
void set_edit_hide(bool edit_hide)
{
editHide = edit_hide;
}
[[nodiscard]] bool is_out() const
{
return out;
}
void set_out(bool out)
{
this->out = out;
}
[[nodiscard]] int get_entity_create_date() const
{
return entityCreateDate;
}
void set_entity_create_date(int entity_create_date)
{
entityCreateDate = entity_create_date;
}
[[nodiscard]] std::string get_text() const
{
return text;
}
void set_text(const std::string& text)
{
this->text = text;
}
[[nodiscard]] std::string get_text_entities() const
{
return textEntities;
}
void set_text_entities(const std::string& text_entities)
{
textEntities = text_entities;
}
[[nodiscard]] std::string get_media_path() const
{
return mediaPath;
}
void set_media_path(const std::string& media_path)
{
mediaPath = media_path;
}
[[nodiscard]] int get_document_type() const
{
return documentType;
}
void set_document_type(int document_type)
{
documentType = document_type;
}
[[nodiscard]] std::string get_document_serialized() const
{
return documentSerialized;
}
void set_document_serialized(const std::string& document_serialized)
{
documentSerialized = document_serialized;
}
[[nodiscard]] std::string get_thumbs_serialized() const
{
return thumbsSerialized;
}
void set_thumbs_serialized(const std::string& thumbs_serialized)
{
thumbsSerialized = thumbs_serialized;
}
[[nodiscard]] std::string get_document_attributes_serialized() const
{
return documentAttributesSerialized;
}
void set_document_attributes_serialized(const std::string& document_attributes_serialized)
{
documentAttributesSerialized = document_attributes_serialized;
}
[[nodiscard]] std::string get_mime_type() const
{
return mimeType;
}
void set_mime_type(const std::string& mime_type)
{
mimeType = mime_type;
}
ID fakeId;
ID userId;
ID dialogId;
ID peerId;
int topMessage;
int lastMessageDate;
int flags;
int entityCreateDate;
};

View file

@ -4,16 +4,17 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "ui/rp_widget.h"
namespace AyuFeatures::StreamerMode
{
bool isEnabled();
void enable();
void disable();
void hideWidgetWindow(QWidget* widget);
void showWidgetWindow(QWidget* widget);
bool isEnabled();
void enable();
void disable();
void hideWidgetWindow(QWidget *widget);
void showWidgetWindow(QWidget *widget);
}

View file

@ -14,30 +14,34 @@
namespace AyuFeatures::StreamerMode
{
bool isEnabledVal;
bool isEnabled()
{
return isEnabledVal;
}
bool isEnabledVal;
void enable()
{
isEnabledVal = true;
}
bool isEnabled()
{
return isEnabledVal;
}
void disable()
{
isEnabledVal = false;
}
void enable()
{
isEnabledVal = true;
}
void hideWidgetWindow(QWidget* widget) {
void disable()
{
isEnabledVal = false;
}
}
void hideWidgetWindow(QWidget *widget)
{
void showWidgetWindow(QWidget* widget) {
}
void showWidgetWindow(QWidget *widget)
{
}
}
}
#endif

View file

@ -14,40 +14,42 @@
namespace AyuFeatures::StreamerMode
{
bool isEnabledVal;
bool isEnabled()
{
return isEnabledVal;
}
bool isEnabledVal;
void enable()
{
auto handle = Core::App().activeWindow()->widget()->psHwnd();
SetWindowDisplayAffinity(handle, WDA_EXCLUDEFROMCAPTURE);
bool isEnabled()
{
return isEnabledVal;
}
isEnabledVal = true;
}
void enable()
{
auto handle = Core::App().activeWindow()->widget()->psHwnd();
SetWindowDisplayAffinity(handle, WDA_EXCLUDEFROMCAPTURE);
void disable()
{
auto handle = Core::App().activeWindow()->widget()->psHwnd();
SetWindowDisplayAffinity(handle, WDA_NONE);
isEnabledVal = true;
}
isEnabledVal = false;
}
void disable()
{
auto handle = Core::App().activeWindow()->widget()->psHwnd();
SetWindowDisplayAffinity(handle, WDA_NONE);
void hideWidgetWindow(QWidget* widget)
{
auto handle = reinterpret_cast<HWND>(widget->window()->winId());
SetWindowDisplayAffinity(handle, WDA_EXCLUDEFROMCAPTURE);
}
isEnabledVal = false;
}
void hideWidgetWindow(QWidget *widget)
{
auto handle = reinterpret_cast<HWND>(widget->window()->winId());
SetWindowDisplayAffinity(handle, WDA_EXCLUDEFROMCAPTURE);
}
void showWidgetWindow(QWidget *widget)
{
auto handle = reinterpret_cast<HWND>(widget->window()->winId());
SetWindowDisplayAffinity(handle, WDA_NONE);
}
void showWidgetWindow(QWidget* widget)
{
auto handle = reinterpret_cast<HWND>(widget->window()->winId());
SetWindowDisplayAffinity(handle, WDA_NONE);
}
}
#endif

View file

@ -9,6 +9,7 @@
#include "ayu/ayu_constants.h"
#include "ayu/database/ayu_database.h"
#include "ayu/utils/ayu_mapper.h"
#include "ayu/utils/telegram_helpers.h"
#include "base/unixtime.h"
@ -18,87 +19,91 @@
#include "history/history.h"
#include "history/history_item.h"
#include "history/history_item_components.h"
#include "main/main_session.h"
namespace AyuMessages
{
std::optional<ayu_messages_controller> controller = std::nullopt;
void initialize()
{
if (controller.has_value())
{
return;
}
std::optional<ayu_messages_controller> controller = std::nullopt;
controller = ayu_messages_controller();
void initialize()
{
if (controller.has_value()) {
return;
}
ayu_messages_controller& getInstance()
{
initialize();
return controller.value();
}
void map(HistoryMessageEdition& edition, not_null<HistoryItem*> item, AyuMessageBase& message)
{
message.userId = item->history()->owner().session().userId().bare;
message.dialogId = getDialogIdFromPeer(item->history()->peer);
message.groupedId = item->groupId().value;
message.peerId = item->from()->id.value; // todo: ???
message.fromId = item->from()->id.value;
if (auto topic = item->history()->asTopic())
{
message.topicId = topic->rootId().bare;
}
message.messageId = item->id.bare;
message.date = item->date();
// message.flags = todo:
message.editDate = edition.editDate;
message.editHide = item->hideEditedBadge();
message.out = item->out();
message.entityCreateDate = base::unixtime::now(); // todo: rework
auto serializedText = serializeTextWithEntities(item);
message.text = serializedText.first;
message.textEntities = serializedText.second;
// todo:
message.mediaPath = "/";
message.documentType = DOCUMENT_TYPE_NONE;
// message.documentSerialized;
// message.thumbsSerialized;
// message.documentAttributesSerialized;
// message.mimeType;
}
void ayu_messages_controller::addEditedMessage(HistoryMessageEdition& edition, not_null<HistoryItem*> item)
{
EditedMessage message;
map(edition, item, message);
AyuDatabase::addEditedMessage(message);
}
std::vector<EditedMessage> ayu_messages_controller::getEditedMessages(HistoryItem* item)
{
auto userId = item->history()->owner().session().userId().bare;
auto dialogId = getDialogIdFromPeer(item->history()->peer);
auto msgId = item->id.bare;
return AyuDatabase::getEditedMessages(userId, dialogId, msgId);
}
bool ayu_messages_controller::hasRevisions(not_null<HistoryItem*> item)
{
auto userId = item->history()->owner().session().userId().bare;
auto dialogId = getDialogIdFromPeer(item->history()->peer);
auto msgId = item->id.bare;
return AyuDatabase::hasRevisions(userId, dialogId, msgId);
}
controller = ayu_messages_controller();
}
ayu_messages_controller &getInstance()
{
initialize();
return controller.value();
}
void map(HistoryMessageEdition &edition, not_null<HistoryItem *> item, EditedMessage &message)
{
message.userId = item->history()->owner().session().userId().bare;
message.dialogId = getDialogIdFromPeer(item->history()->peer);
message.groupedId = item->groupId().value;
message.peerId = item->from()->id.value; // todo: ???
message.fromId = item->from()->id.value;
if (auto topic = item->history()->asTopic()) {
message.topicId = topic->rootId().bare;
}
message.messageId = item->id.bare;
message.date = item->date();
message.flags = AyuMapper::mapItemFlagsToMTPFlags(item);
if (auto edited = item->Get<HistoryMessageEdited>()) {
message.editDate = edited->date;
} else {
message.editDate = base::unixtime::now();
}
message.views = item->viewsCount();
message.entityCreateDate = base::unixtime::now(); // todo: rework
auto serializedText = serializeTextWithEntities(item);
message.text = serializedText.first;
// message.textEntities = serializedText.second;
// todo:
message.mediaPath = "/";
message.documentType = DOCUMENT_TYPE_NONE;
// message.documentSerialized;
// message.thumbsSerialized;
// message.documentAttributesSerialized;
// message.mimeType;
}
void ayu_messages_controller::addEditedMessage(HistoryMessageEdition &edition, not_null<HistoryItem *> item)
{
EditedMessage message;
map(edition, item, message);
AyuDatabase::addEditedMessage(message);
}
std::vector<EditedMessage> ayu_messages_controller::getEditedMessages(HistoryItem *item)
{
auto userId = item->history()->owner().session().userId().bare;
auto dialogId = getDialogIdFromPeer(item->history()->peer);
auto msgId = item->id.bare;
return AyuDatabase::getEditedMessages(userId, dialogId, msgId);
}
bool ayu_messages_controller::hasRevisions(not_null<HistoryItem *> item)
{
auto userId = item->history()->owner().session().userId().bare;
auto dialogId = getDialogIdFromPeer(item->history()->peer);
auto msgId = item->id.bare;
return AyuDatabase::hasRevisions(userId, dialogId, msgId);
}
}

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "ayu/database/entities.h"
@ -13,13 +12,15 @@
namespace AyuMessages
{
class ayu_messages_controller
{
public:
void addEditedMessage(HistoryMessageEdition& edition, not_null<HistoryItem*> item);
std::vector<EditedMessage> getEditedMessages(HistoryItem* item);
bool hasRevisions(not_null<HistoryItem*> item);
};
ayu_messages_controller& getInstance();
class ayu_messages_controller
{
public:
void addEditedMessage(HistoryMessageEdition &edition, not_null<HistoryItem *> item);
std::vector<EditedMessage> getEditedMessages(HistoryItem *item);
bool hasRevisions(not_null<HistoryItem *> item);
};
ayu_messages_controller &getInstance();
}

View file

@ -24,198 +24,183 @@
namespace AyuSync
{
std::optional<ayu_sync_controller> controller = std::nullopt;
bool isAgentDownloaded()
{
return std::filesystem::exists(AgentPath);
std::optional<ayu_sync_controller> controller = std::nullopt;
bool isAgentDownloaded()
{
return std::filesystem::exists(AgentPath);
}
bool isAgentRunning()
{
return isProcessRunning(AgentFilename);
}
void initialize()
{
if (controller.has_value()) {
return;
}
bool isAgentRunning()
{
return isProcessRunning(AgentFilename);
controller = ayu_sync_controller();
}
ayu_sync_controller &getInstance()
{
initialize();
return controller.value();
}
void ayu_sync_controller::initializeAgent()
{
if (!isAgentDownloaded()) {
return;
}
void initialize()
{
if (controller.has_value())
{
return;
if (isAgentRunning()) {
killProcess(AgentFilename);
}
auto configPath = std::filesystem::absolute("./tdata/sync_preferences.json");
auto process = nes::process{AgentPath, {configPath.string(), ""}, nes::process_options::none};
process.detach();
std::thread receiverThread(&ayu_sync_controller::receiver, this);
receiverThread.detach();
initialized = true;
}
void ayu_sync_controller::syncRead(not_null<History *> history, MsgId untilId)
{
if (!initialized) {
return;
}
SyncRead ev;
ev.userId = history->owner().session().userId().bare;
ev.args.dialogId = getDialogIdFromPeer(history->peer);
ev.args.untilId = untilId.bare;
ev.args.unread = history->unreadCount();
pipe->send(ev);
}
void ayu_sync_controller::receiver()
{
pipe = std::make_unique<ayu_pipe_wrapper>();
pipe->connect();
LOG(("Pipe created"));
while (true) {
auto p = pipe->receive();
if (p == std::nullopt) {
continue;
}
controller = ayu_sync_controller();
std::string s = p->dump();
LOG(("[AyuSync] Received message: %1").arg(QString::fromStdString(s)));
invokeHandler(p.value());
}
}
void ayu_sync_controller::invokeHandler(json p)
{
LOG(("Invoking handler on %1").arg(p.dump().c_str()));
auto userId = p["userId"].get<long>();
auto type = p["type"].get<std::string>();
LOG(("userId: %1, type: %2").arg(userId).arg(type.c_str()));
if (!accountExists(userId)) {
LOG(("Sync for unknown account: %1").arg(userId));
return;
}
ayu_sync_controller& getInstance()
{
initialize();
return controller.value();
if (type == "sync_force") {
auto ev = p.get<SyncForce>();
onSyncForce(ev);
}
void ayu_sync_controller::initializeAgent()
{
if (!isAgentDownloaded())
{
return;
}
if (isAgentRunning())
{
killProcess(AgentFilename);
}
auto configPath = std::filesystem::absolute("./tdata/sync_preferences.json");
auto process = nes::process{AgentPath, {configPath.string(), ""}, nes::process_options::none};
process.detach();
std::thread receiverThread(&ayu_sync_controller::receiver, this);
receiverThread.detach();
initialized = true;
else if (type == "sync_batch") {
onSyncBatch(p);
}
void ayu_sync_controller::syncRead(not_null<History*> history, MsgId untilId)
{
if (!initialized)
{
return;
}
SyncRead ev;
ev.userId = history->owner().session().userId().bare;
ev.args.dialogId = getDialogIdFromPeer(history->peer);
ev.args.untilId = untilId.bare;
ev.args.unread = history->unreadCount();
pipe->send(ev);
else if (type == "sync_read") {
auto ev = p.get<SyncRead>();
onSyncRead(ev);
}
else {
LOG(("Unknown sync type: %1").arg(type.c_str()));
}
}
void ayu_sync_controller::receiver()
{
pipe = std::make_unique<ayu_pipe_wrapper>();
pipe->connect();
void ayu_sync_controller::onSyncForce(SyncForce ev)
{
auto session = getSession(ev.userId);
auto histories = session->data().chatsList();
LOG(("Pipe created"));
SyncBatch readsBatchEvent;
readsBatchEvent.userId = ev.userId;
while (true)
{
auto p = pipe->receive();
if (p == std::nullopt)
{
for (const auto &row : histories->indexed()->all()) {
if (const auto history = row->history()) {
auto dialogId = getDialogIdFromPeer(history->peer);
SyncRead readEv;
readEv.userId = ev.userId;
history->calculateFirstUnreadMessage();
auto unreadElement = history->firstUnreadMessage();
if (!unreadElement && history->unreadCount()) {
LOG(("No unread can be calculated for %1").arg(dialogId));
continue;
}
std::string s = p->dump();
LOG(("[AyuSync] Received message: %1").arg(QString::fromStdString(s)));
auto untilId = unreadElement ? unreadElement->data()->id.bare : history->lastMessage()->id.bare;
invokeHandler(p.value());
readEv.args.dialogId = dialogId;
readEv.args.untilId = untilId;
readEv.args.unread = history->unreadCount();
readsBatchEvent.args.events.emplace_back(readEv);
}
}
void ayu_sync_controller::invokeHandler(json p)
{
LOG(("Invoking handler on %1").arg(p.dump().c_str()));
pipe->send(readsBatchEvent);
auto userId = p["userId"].get<long>();
auto type = p["type"].get<std::string>();
// send finish event
SyncForceFinish newEv;
newEv.userId = ev.userId;
LOG(("userId: %1, type: %2").arg(userId).arg(type.c_str()));
pipe->send(newEv);
}
if (!accountExists(userId))
{
LOG(("Sync for unknown account: %1").arg(userId));
return;
}
if (type == "sync_force")
{
auto ev = p.get<SyncForce>();
onSyncForce(ev);
}
else if (type == "sync_batch")
{
onSyncBatch(p);
}
else if (type == "sync_read")
{
auto ev = p.get<SyncRead>();
onSyncRead(ev);
}
else
{
LOG(("Unknown sync type: %1").arg(type.c_str()));
}
}
void ayu_sync_controller::onSyncForce(SyncForce ev)
{
auto session = getSession(ev.userId);
auto histories = session->data().chatsList();
SyncBatch readsBatchEvent;
readsBatchEvent.userId = ev.userId;
for (const auto& row : histories->indexed()->all())
{
if (const auto history = row->history())
{
auto dialogId = getDialogIdFromPeer(history->peer);
SyncRead readEv;
readEv.userId = ev.userId;
history->calculateFirstUnreadMessage();
auto unreadElement = history->firstUnreadMessage();
if (!unreadElement && history->unreadCount())
{
LOG(("No unread can be calculated for %1").arg(dialogId));
continue;
}
auto untilId = unreadElement ? unreadElement->data()->id.bare : history->lastMessage()->id.bare;
readEv.args.dialogId = dialogId;
readEv.args.untilId = untilId;
readEv.args.unread = history->unreadCount();
readsBatchEvent.args.events.emplace_back(readEv);
}
}
pipe->send(readsBatchEvent);
// send finish event
SyncForceFinish newEv;
newEv.userId = ev.userId;
pipe->send(newEv);
}
void ayu_sync_controller::onSyncBatch(json ev)
{
for (auto& item : ev["args"]["events"])
{
invokeHandler(item);
}
}
void ayu_sync_controller::onSyncRead(SyncRead ev)
{
dispatchToMainThread([=]
{
auto session = getSession(ev.userId);
auto history = getHistoryFromDialogId(ev.args.dialogId, session);
if (history->folderKnown())
{
history->inboxRead(ev.args.untilId, ev.args.unread);
}
else
{
LOG(("Unknown dialog %1").arg(ev.args.dialogId));
}
});
void ayu_sync_controller::onSyncBatch(json ev)
{
for (auto &item : ev["args"]["events"]) {
invokeHandler(item);
}
}
void ayu_sync_controller::onSyncRead(SyncRead ev)
{
dispatchToMainThread([=]
{
auto session = getSession(ev.userId);
auto history = getHistoryFromDialogId(ev.args.dialogId, session);
if (history->folderKnown()) {
history->inboxRead(ev.args.untilId, ev.args.unread);
}
else {
LOG(("Unknown dialog %1").arg(ev.args.dialogId));
}
});
}
}

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "models.h"
@ -16,39 +15,44 @@
using json = nlohmann::json;
const std::string AgentFilename =
#ifdef _WIN32
"AyuSync.Agent.exe";
const std::string AgentFilename = "AyuSync.Agent.exe";
#else
"AyuSync.Agent";
const std::string AgentFilename = "AyuSync.Agent";
#endif
const std::string AgentPath = "./AyuSync/" + AgentFilename;
namespace AyuSync
{
class ayu_sync_controller
{
public:
void initializeAgent();
void syncRead(not_null<History*> history, MsgId untilId);
class ayu_sync_controller
{
public:
void initializeAgent();
void onSyncForce(SyncForce ev);
void onSyncBatch(json ev);
void onSyncRead(SyncRead ev);
void syncRead(not_null<History *> history, MsgId untilId);
void invokeHandler(json p);
void onSyncForce(SyncForce ev);
void onSyncBatch(json ev);
void onSyncRead(SyncRead ev);
private:
void receiver();
void invokeHandler(json p);
std::unique_ptr<ayu_pipe_wrapper> pipe;
bool initialized;
};
private:
void receiver();
ayu_sync_controller& getInstance();
std::unique_ptr<ayu_pipe_wrapper> pipe;
bool initialized;
};
ayu_sync_controller &getInstance();
bool isAgentDownloaded();
bool isAgentRunning();
bool isAgentDownloaded();
bool isAgentRunning();
}

View file

@ -1,10 +1,15 @@
// This is the source code of AyuGram for Desktop.
//
// We do not and cannot prevent the use of our code,
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "ayu/libs/json.hpp"
#include <string>
#include <vector>
#include "ayu/libs/json.hpp"
#include "ayu/database/entities.h"
using json = nlohmann::json;
@ -30,7 +35,41 @@ public:
std::vector<json> events;
};
SyncBatchArgs args;
SyncBatchArgs args{};
};
class SyncForce : public SyncEvent
{
public:
explicit SyncForce()
{
type = "sync_force";
}
class SyncForceArgs
{
public:
int fromDate;
};
SyncForceArgs args{};
};
class SyncForceFinish : public SyncEvent
{
public:
explicit SyncForceFinish()
{
type = "sync_force_finish";
}
class SyncForceFinishArgs
{
public:
short dummy; // required to be JSON serializable
};
SyncForceFinishArgs args{};
};
class SyncRead : public SyncEvent
@ -49,50 +88,53 @@ public:
int unread;
};
SyncReadArgs args;
SyncReadArgs args{};
};
class SyncForce : public SyncEvent
class SyncDeletedMessage : public SyncEvent
{
public:
explicit SyncForce()
explicit SyncDeletedMessage()
{
type = "sync_force";
type = "sync_deleted_message";
}
class SyncForceArgs
class SyncDeletedMessageArgs
{
public:
int fromDate;
json message;
};
SyncForceArgs args;
SyncDeletedMessageArgs args{};
};
class SyncForceFinish : public SyncEvent
class SyncEditedMessage : public SyncEvent
{
public:
explicit SyncForceFinish()
explicit SyncEditedMessage()
{
type = "sync_force_finish";
type = "sync_edited_message";
}
class SyncForceFinishArgs
class SyncEditedMessageArgs
{
public:
short dummy; // required to be JSON serializable
json message;
};
SyncForceFinishArgs args;
SyncEditedMessageArgs args{};
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncEvent, type, userId)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncBatch::SyncBatchArgs, events)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncBatch, type, userId, args)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncRead::SyncReadArgs, dialogId, untilId, unread)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncRead, type, userId, args)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncForce::SyncForceArgs, fromDate)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncForce, type, userId, args)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncForceFinish::SyncForceFinishArgs, dummy)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncForceFinish, type, userId, args)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncRead::SyncReadArgs, dialogId, untilId, unread)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncRead, type, userId, args)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncDeletedMessage::SyncDeletedMessageArgs, message)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncDeletedMessage, type, userId, args)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncEditedMessage::SyncEditedMessageArgs, message)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SyncEditedMessage, type, userId, args)

View file

@ -26,14 +26,13 @@ void ayu_pipe_wrapper::send(json p)
bit_converter::i32_to_bytes(length, false, lengthBuff);
os->write(lengthBuff, 4);
os->write(reinterpret_cast<const unsigned char*>(s.c_str()), length);
os->write(reinterpret_cast<const unsigned char *>(s.c_str()), length);
os->flush();
}
std::optional<json> ayu_pipe_wrapper::receive()
{
if (!is->is_open())
{
if (!is->is_open()) {
return std::nullopt;
}
@ -44,16 +43,14 @@ std::optional<json> ayu_pipe_wrapper::receive()
LOG(("ayu_pipe_wrapper::receive() length: %1").arg(length));
if (length <= 0)
{
if (length <= 0) {
return std::nullopt;
}
auto sb = stringbuf();
unsigned char buff[4096];
while (length > 0)
{
while (length > 0) {
auto readSize = std::min(length, static_cast<int>(sizeof(buff)));
is->read(buff, readSize);

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "ayu/libs/json.hpp"

View file

@ -1,3 +1,10 @@
// This is the source code of AyuGram for Desktop.
//
// We do not and cannot prevent the use of our code,
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#include <codecvt>
#include <iostream>
#include <locale>
@ -12,31 +19,27 @@
// A function to check if a process is running by its name
// Bing AI generated
inline bool isProcessRunning(const std::string& name)
inline bool isProcessRunning(const std::string &name)
{
#ifdef _WIN32
// Create a snapshot of all processes
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE)
{
if (snapshot == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to create snapshot\n";
return false;
}
// Iterate over the processes and compare the names
PROCESSENTRY32 entry;
entry.dwSize = sizeof(entry);
if (!Process32First(snapshot, &entry))
{
if (!Process32First(snapshot, &entry)) {
std::cerr << "Failed to get first process\n";
CloseHandle(snapshot);
return false;
}
do
{
do {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string entry_name = converter.to_bytes(entry.szExeFile);
if (name == entry_name)
{
if (name == entry_name) {
// Found a match
CloseHandle(snapshot);
return true;
@ -52,34 +55,29 @@ inline bool isProcessRunning(const std::string& name)
}
// Copilot generated
void killProcess(const std::string& name)
void killProcess(const std::string &name)
{
#ifdef _WIN32
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE)
{
if (snapshot == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to create snapshot\n";
return;
}
// Iterate over the processes and compare the names
PROCESSENTRY32 entry;
entry.dwSize = sizeof(entry);
if (!Process32First(snapshot, &entry))
{
if (!Process32First(snapshot, &entry)) {
std::cerr << "Failed to get first process\n";
CloseHandle(snapshot);
return;
}
do
{
do {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string entry_name = converter.to_bytes(entry.szExeFile);
if (name == entry_name)
{
if (name == entry_name) {
// Found a match
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, entry.th32ProcessID);
if (hProcess != nullptr)
{
if (hProcess != nullptr) {
TerminateProcess(hProcess, 9);
CloseHandle(hProcess);
}

View file

@ -9,10 +9,13 @@
#include "ayu/ayu_settings.h"
static QString LAST_LOADED_NAME;
static QImage LAST_LOADED;
static QImage LAST_LOADED_NO_MARGIN;
void loadAppIco() {
void loadAppIco()
{
auto settings = &AyuSettings::getInstance();
QString appDataPath = QDir::fromNativeSeparators(qgetenv("APPDATA"));
@ -31,8 +34,7 @@ void loadAppIco() {
void loadIcons()
{
auto settings = &AyuSettings::getInstance();
if (LAST_LOADED_NAME != settings->appIcon)
{
if (LAST_LOADED_NAME != settings->appIcon) {
LAST_LOADED_NAME = settings->appIcon;
LAST_LOADED = QImage(qsl(":/gui/art/ayu/%1/logo256.png").arg(settings->appIcon));

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
void loadAppIco();

View file

@ -9,10 +9,12 @@
namespace AyuUi
{
std::unique_ptr<Lottie::Icon> getLottie(const QString& text)
{
// todo: some kind of mapping
// Lottie::MakeIcon({.json = QString(), .sizeOverride = {24, 24}});
return nullptr;
}
std::unique_ptr<Lottie::Icon> getLottie(const QString &text)
{
// todo: some kind of mapping
// Lottie::MakeIcon({.json = QString(), .sizeOverride = {24, 24}});
return nullptr;
}
}

View file

@ -4,12 +4,13 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "lottie/lottie_icon.h"
namespace AyuUi
{
std::unique_ptr<Lottie::Icon> getLottie(const QString& text);
std::unique_ptr<Lottie::Icon> getLottie(const QString &text);
}

View file

@ -17,48 +17,52 @@
namespace AyuUi
{
ConfirmationBox::ConfirmationBox(
QWidget*,
not_null<Window::SessionController*> controller) : _controller(controller)
{
//
}
void ConfirmationBox::prepare()
{
_text.create(this, tr::ayu_ReadConfirmationBoxQuestion(), st::boxLabel);
auto fullHeight = st::boxPadding.top()
+ _text->height()
+ st::boxPadding.bottom();
setDimensions(st::boxWidth, fullHeight);
addButton(tr::ayu_ReadConfirmationBoxActionText(), [=, this]
{
ReadAllPeers();
closeBox();
});
addButton(tr::lng_cancel(), [=, this] { closeBox(); });
}
void ConfirmationBox::resizeEvent(QResizeEvent* e)
{
BoxContent::resizeEvent(e);
const auto& padding = st::boxPadding;
_text->moveToLeft(padding.left(), padding.top());
}
void ConfirmationBox::ReadAllPeers()
{
auto settings = &AyuSettings::getInstance();
auto prev = settings->sendReadMessages;
settings->set_sendReadMessages(true);
auto chats = _controller->session().data().chatsList();
Window::MarkAsReadChatListHack(chats);
settings->set_sendReadMessages(prev);
}
ConfirmationBox::ConfirmationBox(
QWidget *,
not_null<Window::SessionController *> controller)
: _controller(controller)
{
//
}
void ConfirmationBox::prepare()
{
_text.create(this, tr::ayu_ReadConfirmationBoxQuestion(), st::boxLabel);
auto fullHeight = st::boxPadding.top()
+ _text->height()
+ st::boxPadding.bottom();
setDimensions(st::boxWidth, fullHeight);
addButton(tr::ayu_ReadConfirmationBoxActionText(), [=, this]
{
ReadAllPeers();
closeBox();
});
addButton(tr::lng_cancel(), [=, this]
{ closeBox(); });
}
void ConfirmationBox::resizeEvent(QResizeEvent *e)
{
BoxContent::resizeEvent(e);
const auto &padding = st::boxPadding;
_text->moveToLeft(padding.left(), padding.top());
}
void ConfirmationBox::ReadAllPeers()
{
auto settings = &AyuSettings::getInstance();
auto prev = settings->sendReadMessages;
settings->set_sendReadMessages(true);
auto chats = _controller->session().data().chatsList();
Window::MarkAsReadChatListHack(chats);
settings->set_sendReadMessages(prev);
}
}

View file

@ -4,26 +4,29 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "ui/layers/box_content.h"
#include "window/window_main_menu.h"
namespace AyuUi
{
class ConfirmationBox : public Ui::BoxContent
{
public:
ConfirmationBox(QWidget*, not_null<Window::SessionController*> controller);
protected:
void prepare() override;
class ConfirmationBox : public Ui::BoxContent
{
public:
ConfirmationBox(QWidget *, not_null<Window::SessionController *> controller);
void resizeEvent(QResizeEvent* e) override;
protected:
void prepare() override;
private:
void ReadAllPeers();
void resizeEvent(QResizeEvent *e) override;
private:
void ReadAllPeers();
not_null<Window::SessionController *> _controller;
object_ptr<Ui::FlatLabel> _text = {nullptr};
};
not_null<Window::SessionController*> _controller;
object_ptr<Ui::FlatLabel> _text = {nullptr};
};
}

View file

@ -28,7 +28,8 @@
#include "ayu/ayu_settings.h"
EditDeletedMarkBox::EditDeletedMarkBox(QWidget*) :
EditDeletedMarkBox::EditDeletedMarkBox(QWidget *)
:
_text(
this,
st::defaultInputField,
@ -47,12 +48,16 @@ void EditDeletedMarkBox::prepare()
newHeight += st::boxPadding.bottom() + st::contactPadding.bottom();
setDimensions(st::boxWidth, newHeight);
addLeftButton(tr::ayu_BoxActionReset(), [=] { _text->setText(defaultDeletedMark); });
addLeftButton(tr::ayu_BoxActionReset(), [=]
{ _text->setText(defaultDeletedMark); });
addButton(tr::lng_settings_save(), [=] { save(); });
addButton(tr::lng_cancel(), [=] { closeBox(); });
addButton(tr::lng_settings_save(), [=]
{ save(); });
addButton(tr::lng_cancel(), [=]
{ closeBox(); });
connect(_text, &Ui::InputField::submitted, [=] { submit(); });
connect(_text, &Ui::InputField::submitted, [=]
{ submit(); });
}
void EditDeletedMarkBox::setInnerFocus()
@ -62,26 +67,24 @@ void EditDeletedMarkBox::setInnerFocus()
void EditDeletedMarkBox::submit()
{
if (_text->getLastText().trimmed().isEmpty())
{
if (_text->getLastText().trimmed().isEmpty()) {
_text->setFocus();
_text->showError();
}
else
{
else {
save();
}
}
void EditDeletedMarkBox::resizeEvent(QResizeEvent* e)
void EditDeletedMarkBox::resizeEvent(QResizeEvent *e)
{
BoxContent::resizeEvent(e);
_text->resize(
width()
- st::boxPadding.left()
- st::newGroupInfoPadding.left()
- st::boxPadding.right(),
- st::boxPadding.left()
- st::newGroupInfoPadding.left()
- st::boxPadding.right(),
_text->height());
const auto left = st::boxPadding.left() + st::newGroupInfoPadding.left();

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "base/timer.h"
@ -14,14 +13,14 @@
class EditDeletedMarkBox : public Ui::BoxContent
{
public:
EditDeletedMarkBox(QWidget*);
EditDeletedMarkBox(QWidget *);
protected:
void setInnerFocus() override;
void prepare() override;
void resizeEvent(QResizeEvent* e) override;
void resizeEvent(QResizeEvent *e) override;
private:
void submit();

View file

@ -28,7 +28,8 @@
#include "ayu/ayu_settings.h"
EditEditedMarkBox::EditEditedMarkBox(QWidget*) :
EditEditedMarkBox::EditEditedMarkBox(QWidget *)
:
_text(
this,
st::defaultInputField,
@ -37,7 +38,6 @@ EditEditedMarkBox::EditEditedMarkBox(QWidget*) :
{
}
void EditEditedMarkBox::prepare()
{
const auto defaultEditedMark = tr::lng_edited(tr::now);
@ -48,14 +48,17 @@ void EditEditedMarkBox::prepare()
newHeight += st::boxPadding.bottom() + st::contactPadding.bottom();
setDimensions(st::boxWidth, newHeight);
addLeftButton(tr::ayu_BoxActionReset(), [=] { _text->setText(defaultEditedMark); });
addButton(tr::lng_settings_save(), [=] { save(); });
addButton(tr::lng_cancel(), [=] { closeBox(); });
addLeftButton(tr::ayu_BoxActionReset(), [=]
{ _text->setText(defaultEditedMark); });
addButton(tr::lng_settings_save(), [=]
{ save(); });
addButton(tr::lng_cancel(), [=]
{ closeBox(); });
connect(_text, &Ui::InputField::submitted, [=] { submit(); });
connect(_text, &Ui::InputField::submitted, [=]
{ submit(); });
}
void EditEditedMarkBox::setInnerFocus()
{
_text->setFocusFast();
@ -63,26 +66,24 @@ void EditEditedMarkBox::setInnerFocus()
void EditEditedMarkBox::submit()
{
if (_text->getLastText().trimmed().isEmpty())
{
if (_text->getLastText().trimmed().isEmpty()) {
_text->setFocus();
_text->showError();
}
else
{
else {
save();
}
}
void EditEditedMarkBox::resizeEvent(QResizeEvent* e)
void EditEditedMarkBox::resizeEvent(QResizeEvent *e)
{
BoxContent::resizeEvent(e);
_text->resize(
width()
- st::boxPadding.left()
- st::newGroupInfoPadding.left()
- st::boxPadding.right(),
- st::boxPadding.left()
- st::newGroupInfoPadding.left()
- st::boxPadding.right(),
_text->height());
const auto left = st::boxPadding.left() + st::newGroupInfoPadding.left();

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "base/timer.h"
@ -14,14 +13,14 @@
class EditEditedMarkBox : public Ui::BoxContent
{
public:
EditEditedMarkBox(QWidget*);
EditEditedMarkBox(QWidget *);
protected:
void setInnerFocus() override;
void prepare() override;
void resizeEvent(QResizeEvent* e) override;
void resizeEvent(QResizeEvent *e) override;
private:
void submit();

View file

@ -20,59 +20,58 @@ using namespace Settings;
namespace AyuUi
{
MessageHistoryBox::MessageHistoryBox(QWidget*, HistoryItem* item)
: _content(this), _scroll(base::make_unique_q<Ui::ScrollArea>(this, st::boxScroll))
{
setupControls();
addEditedMessagesToLayout(item);
}
void MessageHistoryBox::setupControls()
{
_content.create(this);
MessageHistoryBox::MessageHistoryBox(QWidget *, HistoryItem *item)
: _content(this), _scroll(base::make_unique_q<Ui::ScrollArea>(this, st::boxScroll))
{
setupControls();
addEditedMessagesToLayout(item);
}
_content->resizeToWidth(st::boxWideWidth);
_content->moveToLeft(0, 0);
void MessageHistoryBox::setupControls()
{
_content.create(this);
_content->heightValue(
) | start_to_stream(_contentHeight, _content->lifetime());
_content->resizeToWidth(st::boxWideWidth);
_content->moveToLeft(0, 0);
_scroll->setOwnedWidget(
object_ptr<RpWidget>::fromRaw(_content));
}
_content->heightValue(
) | start_to_stream(_contentHeight, _content->lifetime());
void MessageHistoryBox::resizeEvent(QResizeEvent* e)
{
_scroll->resize(width(), height() - st::boxPhotoPadding.top() - st::boxPadding.bottom());
_scroll->move(0, st::boxPadding.top());
_scroll->setOwnedWidget(
object_ptr<RpWidget>::fromRaw(_content));
}
if (_content)
{
_content->resize(_scroll->width(), _content->height());
}
}
void MessageHistoryBox::resizeEvent(QResizeEvent *e)
{
_scroll->resize(width(), height() - st::boxPhotoPadding.top() - st::boxPadding.bottom());
_scroll->move(0, st::boxPadding.top());
void MessageHistoryBox::prepare()
{
setTitle(tr::ayu_EditsHistoryTitle());
setDimensions(st::boxWideWidth, 900);
SetupShadowsToScrollContent(this, _scroll, _contentHeight.events());
}
void MessageHistoryBox::addEditedMessagesToLayout(HistoryItem* item)
{
auto messages = AyuMessages::getInstance().getEditedMessages(item);
if (messages.empty())
{
return;
}
for (const auto& message : messages)
{
AddSkip(_content);
AddDividerText(_content, rpl::single(QString::fromStdString(message.text)));
AddSkip(_content);
}
if (_content) {
_content->resize(_scroll->width(), _content->height());
}
}
void MessageHistoryBox::prepare()
{
setTitle(tr::ayu_EditsHistoryTitle());
setDimensions(st::boxWideWidth, 900);
SetupShadowsToScrollContent(this, _scroll, _contentHeight.events());
}
void MessageHistoryBox::addEditedMessagesToLayout(HistoryItem *item)
{
auto messages = AyuMessages::getInstance().getEditedMessages(item);
if (messages.empty()) {
return;
}
for (const auto &message : messages) {
AddSkip(_content);
AddDividerText(_content, rpl::single(QString::fromStdString(message.text)));
AddSkip(_content);
}
}
}

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "history/history_item.h"
@ -14,24 +13,26 @@
namespace AyuUi
{
class MessageHistoryBox : public Ui::BoxContent
{
public:
MessageHistoryBox(QWidget*, HistoryItem* item);
protected:
void prepare() override;
class MessageHistoryBox : public Ui::BoxContent
{
public:
MessageHistoryBox(QWidget *, HistoryItem *item);
void resizeEvent(QResizeEvent* e) override;
protected:
void prepare() override;
private:
void setupControls();
void resizeEvent(QResizeEvent *e) override;
void addEditedMessagesToLayout(HistoryItem* item);
private:
void setupControls();
object_ptr<Ui::VerticalLayout> _content;
const base::unique_qptr<Ui::ScrollArea> _scroll;
void addEditedMessagesToLayout(HistoryItem *item);
object_ptr<Ui::VerticalLayout> _content;
const base::unique_qptr<Ui::ScrollArea> _scroll;
rpl::event_stream<int> _contentHeight;
};
rpl::event_stream<int> _contentHeight;
};
}

View file

@ -14,112 +14,105 @@
namespace AyuUi
{
void VoiceConfirmBox(not_null<Ui::GenericBox*> box, Ui::ConfirmBoxArgs&& args)
void VoiceConfirmBox(not_null<Ui::GenericBox *> box, Ui::ConfirmBoxArgs &&args)
{
const auto weak = MakeWeak(box);
const auto lifetime = box->lifetime().make_state<rpl::lifetime>();
v::match(args.text, [](v::null_t)
{
const auto weak = MakeWeak(box);
const auto lifetime = box->lifetime().make_state<rpl::lifetime>();
}, [&](auto &&)
{
const auto label = box->addRow(
object_ptr<Ui::FlatLabel>(
box.get(),
v::text::take_marked(std::move(args.text)),
args.labelStyle ? *args.labelStyle : st::boxLabel),
st::boxPadding);
if (args.labelFilter) {
label->setClickHandlerFilter(std::move(args.labelFilter));
}
});
v::match(args.text, [](v::null_t)
{
}, [&](auto&&)
{
const auto label = box->addRow(
object_ptr<Ui::FlatLabel>(
box.get(),
v::text::take_marked(std::move(args.text)),
args.labelStyle ? *args.labelStyle : st::boxLabel),
st::boxPadding);
if (args.labelFilter)
{
label->setClickHandlerFilter(std::move(args.labelFilter));
}
});
const auto prepareCallback = [&](Ui::ConfirmBoxArgs::Callback& callback)
const auto prepareCallback = [&](Ui::ConfirmBoxArgs::Callback &callback)
{
return [=, confirmed = std::move(callback)]()
{
return [=, confirmed = std::move(callback)]()
{
if (const auto callbackPtr = std::get_if<1>(&confirmed))
{
if (auto callback = (*callbackPtr))
{
callback();
}
if (const auto callbackPtr = std::get_if<1>(&confirmed)) {
if (auto callback = (*callbackPtr)) {
callback();
}
else if (const auto callbackPtr = std::get_if<2>(&confirmed))
{
if (auto callback = (*callbackPtr))
{
callback(crl::guard(weak, [=] { weak->closeBox(); }));
}
}
else if (const auto callbackPtr = std::get_if<2>(&confirmed)) {
if (auto callback = (*callbackPtr)) {
callback(crl::guard(weak, [=]
{ weak->closeBox(); }));
}
else if (weak)
{
weak->closeBox();
}
};
}
else if (weak) {
weak->closeBox();
}
};
};
const auto& defaultButtonStyle = box->getDelegate()->style().button;
const auto &defaultButtonStyle = box->getDelegate()->style().button;
const auto confirmButton = box->addButton(
v::text::take_plain(std::move(args.confirmText), tr::lng_box_ok()),
[=, c = prepareCallback(args.confirmed)]()
const auto confirmButton = box->addButton(
v::text::take_plain(std::move(args.confirmText), tr::lng_box_ok()),
[=, c = prepareCallback(args.confirmed)]()
{
lifetime->destroy();
c();
weak->closeBox();
},
args.confirmStyle ? *args.confirmStyle : defaultButtonStyle);
box->events(
) | start_with_next([=](not_null<QEvent *> e)
{
if ((e->type() != QEvent::KeyPress) || !confirmButton) {
return;
}
const auto k = static_cast<QKeyEvent *>(e.get());
if (k->key() == Qt::Key_Enter || k->key() == Qt::Key_Return) {
confirmButton->clicked(Qt::KeyboardModifiers(), Qt::LeftButton);
}
}, box->lifetime());
if (!args.inform) {
const auto cancelButton = box->addButton(
v::text::take_plain(std::move(args.cancelText), tr::lng_cancel()),
crl::guard(weak, [=, c = prepareCallback(args.cancelled)]()
{
lifetime->destroy();
c();
}),
args.cancelStyle ? *args.cancelStyle : defaultButtonStyle);
weak->closeBox();
},
args.confirmStyle ? *args.confirmStyle : defaultButtonStyle);
box->events(
) | start_with_next([=](not_null<QEvent*> e)
box->boxClosing(
) | start_with_next(crl::guard(cancelButton, [=]
{
if ((e->type() != QEvent::KeyPress) || !confirmButton)
{
return;
}
const auto k = static_cast<QKeyEvent*>(e.get());
if (k->key() == Qt::Key_Enter || k->key() == Qt::Key_Return)
{
confirmButton->clicked(Qt::KeyboardModifiers(), Qt::LeftButton);
}
}, box->lifetime());
if (!args.inform)
{
const auto cancelButton = box->addButton(
v::text::take_plain(std::move(args.cancelText), tr::lng_cancel()),
crl::guard(weak, [=, c = prepareCallback(args.cancelled)]()
{
lifetime->destroy();
c();
}),
args.cancelStyle ? *args.cancelStyle : defaultButtonStyle);
box->boxClosing(
) | start_with_next(crl::guard(cancelButton, [=]
{
cancelButton->clicked(Qt::KeyboardModifiers(), Qt::LeftButton);
}), *lifetime);
}
if (args.strictCancel)
{
lifetime->destroy();
}
cancelButton->clicked(Qt::KeyboardModifiers(), Qt::LeftButton);
}), *lifetime);
}
object_ptr<Ui::GenericBox> MakeConfirmBox(Ui::ConfirmBoxArgs&& args)
{
return Box(VoiceConfirmBox, std::move(args));
if (args.strictCancel) {
lifetime->destroy();
}
}
object_ptr<Ui::GenericBox> MakeConfirmBox(Ui::ConfirmBoxArgs &&args)
{
return Box(VoiceConfirmBox, std::move(args));
}
object_ptr<Ui::GenericBox> MakeInformBox(v::text::data text)
{
return MakeConfirmBox({
.text = std::move(text),
.inform = true,
});
}
object_ptr<Ui::GenericBox> MakeInformBox(v::text::data text)
{
return MakeConfirmBox({
.text = std::move(text),
.inform = true,
});
}
} // namespace AyuUi

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "ui/boxes/confirm_box.h"
@ -13,10 +12,12 @@
namespace AyuUi
{
void VoiceConfirmBox(not_null<Ui::GenericBox*> box, Ui::ConfirmBoxArgs&& args);
[[nodiscard]] object_ptr<Ui::GenericBox> MakeConfirmBox(
Ui::ConfirmBoxArgs&& args);
void VoiceConfirmBox(not_null<Ui::GenericBox *> box, Ui::ConfirmBoxArgs &&args);
[[nodiscard]] object_ptr<Ui::GenericBox> MakeConfirmBox(
Ui::ConfirmBoxArgs &&args);
[[nodiscard]] object_ptr<Ui::GenericBox> MakeInformBox(v::text::data text);
[[nodiscard]] object_ptr<Ui::GenericBox> MakeInformBox(v::text::data text);
} // namespace Ui

View file

@ -4,11 +4,9 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#include "context_menu.h"
#include "ayu/ui/context_menu/context_menu.h"
#include "lang_auto.h"
#include "ayu/ayu_state.h"
#include "ayu/database/ayu_database.h"
#include "ayu/messages/ayu_messages_controller.h"
#include "ayu/ui/boxes/message_history_box.h"
@ -17,46 +15,49 @@
#include "styles/style_chat.h"
#include "ui/widgets/popup_menu.h"
#include "ayu/ui/sections/edited/edited_log_section.h"
namespace AyuUi
{
AyuPopupMenu::AyuPopupMenu(HistoryInner* parent)
{
_ayuSubMenu = std::make_unique<Ui::PopupMenu>(parent, st::popupMenuWithIcons);
}
void AyuPopupMenu::addHistoryAction(HistoryItem* item)
{
if (AyuMessages::getInstance().hasRevisions(item))
AyuPopupMenu::AyuPopupMenu(HistoryInner *parent)
{
_ayuSubMenu = std::make_unique<Ui::PopupMenu>(parent, st::popupMenuWithIcons);
}
void AyuPopupMenu::addHistoryAction(HistoryItem *item)
{
if (AyuMessages::getInstance().hasRevisions(item)) {
_ayuSubMenu->addAction(tr::ayu_EditsHistoryMenuText(tr::now), [=]
{
_ayuSubMenu->addAction(tr::ayu_EditsHistoryMenuText(tr::now), [=]
{
auto box = Box<MessageHistoryBox>(item);
show(std::move(box));
}, &st::menuIconInfo);
}
item->history()->session().tryResolveWindow()->showSection(std::make_shared<EditedLog::SectionMemento>(item->history()->peer, item));
}, &st::menuIconInfo);
}
}
void AyuPopupMenu::addHideMessageAction(HistoryItem* item) const
void AyuPopupMenu::addHideMessageAction(HistoryItem *item) const
{
const auto settings = &AyuSettings::getInstance();
const auto history = item->history();
_ayuSubMenu->addAction(tr::ayu_ContextHideMessage(tr::now), [=]()
{
const auto settings = &AyuSettings::getInstance();
const auto history = item->history();
_ayuSubMenu->addAction(tr::ayu_ContextHideMessage(tr::now), [=]()
{
const auto initSaveDeleted = settings->saveDeletedMessages;
const auto initSaveDeleted = settings->saveDeletedMessages;
settings->set_keepDeletedMessages(false);
history->destroyMessage(item);
settings->set_keepDeletedMessages(initSaveDeleted);
}, &st::menuIconClear);
}
settings->set_keepDeletedMessages(false);
history->destroyMessage(item);
settings->set_keepDeletedMessages(initSaveDeleted);
}, &st::menuIconClear);
}
void AyuPopupMenu::addReadUntilAction(HistoryItem* item) const
void AyuPopupMenu::addReadUntilAction(HistoryItem *item) const
{
const auto history = item->history();
_ayuSubMenu->addAction(tr::ayu_ReadUntilMenuText(tr::now), [=]()
{
const auto history = item->history();
_ayuSubMenu->addAction(tr::ayu_ReadUntilMenuText(tr::now), [=]()
{
AyuState::setAllowSendReadPacket(true);
history->session().data().histories().readInboxOnNewMessage(item);
}, &st::menuIconShowInChat);
}
AyuState::setAllowSendReadPacket(true);
history->session().data().histories().readInboxOnNewMessage(item);
}, &st::menuIconShowInChat);
}
} // namespace AyuUi

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "mainwindow.h"
@ -78,22 +77,24 @@
#include "history/view/history_view_context_menu.h"
#include <ayu/ayu_settings.h>
#include <styles/style_info.h>
#include "ayu/ayu_settings.h"
#include "styles/style_info.h"
namespace AyuUi
{
class AyuPopupMenu
{
public:
AyuPopupMenu(HistoryInner* parent);
void addHistoryAction(HistoryItem* item);
class AyuPopupMenu
{
public:
AyuPopupMenu(HistoryInner *parent);
void addHideMessageAction(HistoryItem* item) const;
void addHistoryAction(HistoryItem *item);
void addReadUntilAction(HistoryItem* item) const;
void addHideMessageAction(HistoryItem *item) const;
void addReadUntilAction(HistoryItem *item) const;
std::unique_ptr<Ui::PopupMenu> _ayuSubMenu;
};
std::unique_ptr<Ui::PopupMenu> _ayuSubMenu;
};
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,312 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "history/view/history_view_element.h"
#include "ayu/ui/sections/edited/edited_log_item.h"
#include "ayu/ui/sections/edited/edited_log_section.h"
#include "menu/menu_antispam_validator.h"
#include "ui/rp_widget.h"
#include "ui/effects/animations.h"
#include "ui/widgets/tooltip.h"
#include "mtproto/sender.h"
#include "base/timer.h"
struct ChatRestrictionsInfo;
namespace Main
{
class Session;
} // namespace Main
namespace HistoryView
{
class Element;
struct TextState;
struct StateRequest;
enum class CursorState : char;
enum class PointState : char;
} // namespace HistoryView
namespace Ui
{
class PopupMenu;
class ChatStyle;
struct PeerUserpicView;
} // namespace Ui
namespace Window
{
class SessionController;
} // namespace Window
namespace EditedLog
{
class SectionMemento;
class InnerWidget final
: public Ui::RpWidget, public Ui::AbstractTooltipShower, public HistoryView::ElementDelegate
{
public:
InnerWidget(
QWidget *parent,
not_null<Window::SessionController *> controller,
not_null<PeerData *> peer,
not_null<HistoryItem *> item);
[[nodiscard]] Main::Session &session() const;
[[nodiscard]] not_null<Ui::ChatTheme *> theme() const
{
return _theme.get();
}
[[nodiscard]] rpl::producer<int> scrollToSignal() const;
[[nodiscard]] not_null<PeerData *> channel() const
{
return _peer;
}
// Set the correct scroll position after being resized.
void restoreScrollPosition();
void resizeToWidth(int newWidth, int minHeight)
{
_minHeight = minHeight;
return TWidget::resizeToWidth(newWidth);
}
void saveState(not_null<SectionMemento *> memento);
void restoreState(not_null<SectionMemento *> memento);
// Ui::AbstractTooltipShower interface.
QString tooltipText() const override;
QPoint tooltipPos() const override;
bool tooltipWindowActive() const override;
// HistoryView::ElementDelegate interface.
HistoryView::Context elementContext() override;
bool elementUnderCursor(
not_null<const HistoryView::Element *> view) override;
[[nodiscard]] float64 elementHighlightOpacity(
not_null<const HistoryItem *> item) const override;
bool elementInSelectionMode() override;
bool elementIntersectsRange(
not_null<const HistoryView::Element *> view,
int from,
int till) override;
void elementStartStickerLoop(
not_null<const HistoryView::Element *> view) override;
void elementShowPollResults(
not_null<PollData *> poll,
FullMsgId context) override;
void elementOpenPhoto(
not_null<PhotoData *> photo,
FullMsgId context) override;
void elementOpenDocument(
not_null<DocumentData *> document,
FullMsgId context,
bool showInMediaView = false) override;
void elementCancelUpload(const FullMsgId &context) override;
void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) override;
bool elementAnimationsPaused() override;
bool elementHideReply(
not_null<const HistoryView::Element *> view) override;
bool elementShownUnread(
not_null<const HistoryView::Element *> view) override;
void elementSendBotCommand(
const QString &command,
const FullMsgId &context) override;
void elementHandleViaClick(not_null<UserData *> bot) override;
bool elementIsChatWide() override;
not_null<Ui::PathShiftGradient *> elementPathShiftGradient() override;
void elementReplyTo(const FullMsgId &to) override;
void elementStartInteraction(
not_null<const HistoryView::Element *> view) override;
void elementStartPremium(
not_null<const HistoryView::Element *> view,
HistoryView::Element *replacing) override;
void elementCancelPremium(
not_null<const HistoryView::Element *> view) override;
QString elementAuthorRank(
not_null<const HistoryView::Element *> view) override;
~InnerWidget();
protected:
void visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) override;
void paintEvent(QPaintEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseDoubleClickEvent(QMouseEvent *e) override;
void enterEventHook(QEnterEvent *e) override;
void leaveEventHook(QEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e) override;
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private:
using Element = HistoryView::Element;
enum class Direction
{
Up,
Down,
};
enum class MouseAction
{
None,
PrepareDrag,
Dragging,
Selecting,
};
enum class EnumItemsDirection
{
TopToBottom,
BottomToTop,
};
using TextState = HistoryView::TextState;
using CursorState = HistoryView::CursorState;
using PointState = HistoryView::PointState;
using StateRequest = HistoryView::StateRequest;
void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button);
void mouseActionUpdate(const QPoint &screenPos);
void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button);
void mouseActionCancel();
void updateSelected();
void performDrag();
int itemTop(not_null<const Element *> view) const;
void repaintItem(const Element *view);
void refreshItem(not_null<const Element *> view);
void resizeItem(not_null<Element *> view);
QPoint mapPointToItem(QPoint point, const Element *view) const;
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
void savePhotoToFile(not_null<PhotoData *> photo);
void saveDocumentToFile(not_null<DocumentData *> document);
void copyContextImage(not_null<PhotoData *> photo);
void showStickerPackInfo(not_null<DocumentData *> document);
void cancelContextDownload(not_null<DocumentData *> document);
void showContextInFolder(not_null<DocumentData *> document);
void openContextGif(FullMsgId itemId);
void copyContextText(FullMsgId itemId);
void copySelectedText();
TextForMimeData getSelectedText() const;
void updateVisibleTopItem();
void itemsAdded(Direction direction, int addedCount);
void updateSize();
void updateEmptyText();
void paintEmpty(Painter &p, not_null<const Ui::ChatStyle *> st);
void addEvents(Direction direction);
Element *viewForItem(const HistoryItem *item);
void toggleScrollDateShown();
void repaintScrollDateCallback();
bool displayScrollDate() const;
void scrollDateHide();
void scrollDateCheck();
void scrollDateHideByTimer();
// This function finds all history items that are displayed and calls template method
// for each found message (in given direction) in the passed history with passed top offset.
//
// Method has "bool (*Method)(not_null<Element*> view, int itemtop, int itembottom)" signature
// if it returns false the enumeration stops immidiately.
template<EnumItemsDirection direction, typename Method>
void enumerateItems(Method method);
// This function finds all userpics on the left that are displayed and calls template method
// for each found userpic (from the top to the bottom) using enumerateItems() method.
//
// Method has "bool (*Method)(not_null<Element*> view, int userpicTop)" signature
// if it returns false the enumeration stops immediately.
template<typename Method>
void enumerateUserpics(Method method);
// This function finds all date elements that are displayed and calls template method
// for each found date element (from the bottom to the top) using enumerateItems() method.
//
// Method has "bool (*Method)(not_null<HistoryItem*> item, int itemtop, int dateTop)" signature
// if it returns false the enumeration stops immediately.
template<typename Method>
void enumerateDates(Method method);
const not_null<Window::SessionController *> _controller;
const not_null<PeerData *> _peer;
const not_null<HistoryItem *> _item;
const not_null<History *> _history;
MTP::Sender _api;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
std::shared_ptr<Ui::ChatTheme> _theme;
std::vector<OwnedItem> _items;
std::set<uint64> _eventIds;
std::map<not_null<const HistoryItem *>, not_null<Element *>> _itemsByData;
base::flat_map<not_null<const HistoryItem *>, TimeId> _itemDates;
base::flat_set<FullMsgId> _animatedStickersPlayed;
base::flat_map<not_null<PeerData *>, Ui::PeerUserpicView> _userpics;
base::flat_map<not_null<PeerData *>, Ui::PeerUserpicView> _userpicsCache;
int _itemsTop = 0;
int _itemsWidth = 0;
int _itemsHeight = 0;
int _minHeight = 0;
int _visibleTop = 0;
int _visibleBottom = 0;
Element *_visibleTopItem = nullptr;
int _visibleTopFromItem = 0;
bool _isChatWide = false;
bool _scrollDateShown = false;
Ui::Animations::Simple _scrollDateOpacity;
SingleQueuedInvokation _scrollDateCheck;
base::Timer _scrollDateHideTimer;
Element *_scrollDateLastItem = nullptr;
int _scrollDateLastItemTop = 0;
// Don't load anything until the memento was read.
bool _upLoaded = true;
bool _downLoaded = true;
bool _filterChanged = false;
Ui::Text::String _emptyText;
MouseAction _mouseAction = MouseAction::None;
TextSelectType _mouseSelectType = TextSelectType::Letters;
QPoint _dragStartPosition;
QPoint _mousePosition;
Element *_mouseActionItem = nullptr;
CursorState _mouseCursorState = CursorState();
uint16 _mouseTextSymbol = 0;
bool _pressWasInactive = false;
Element *_selectedItem = nullptr;
TextSelection _selectedText;
bool _wasSelectedText = false; // was some text selected in current drag action
Qt::CursorShape _cursor = style::cur_default;
base::unique_qptr<Ui::PopupMenu> _menu;
QPoint _trippleClickPoint;
base::Timer _trippleClickTimer;
rpl::event_stream<int> _scrollToSignal;
};
} // namespace EditedLog

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,67 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "ayu/database/entities.h"
class History;
namespace HistoryView
{
class ElementDelegate;
class Element;
} // namespace HistoryView
namespace EditedLog
{
class OwnedItem;
void GenerateItems(
not_null<HistoryView::ElementDelegate *> delegate,
not_null<History *> history,
EditedMessage message,
Fn<void(OwnedItem item, TimeId sentDate, MsgId)> callback);
// Smart pointer wrapper for HistoryItem* that destroys the owned item.
class OwnedItem
{
public:
OwnedItem(std::nullptr_t = nullptr);
OwnedItem(
not_null<HistoryView::ElementDelegate *> delegate,
not_null<HistoryItem *> data);
OwnedItem(const OwnedItem &other) = delete;
OwnedItem &operator=(const OwnedItem &other) = delete;
OwnedItem(OwnedItem &&other);
OwnedItem &operator=(OwnedItem &&other);
~OwnedItem();
[[nodiscard]] HistoryView::Element *get() const
{
return _view.get();
}
[[nodiscard]] HistoryView::Element *operator->() const
{
return get();
}
[[nodiscard]] operator HistoryView::Element *() const
{
return get();
}
void refreshView(not_null<HistoryView::ElementDelegate *> delegate);
void clearView();
private:
HistoryItem *_data = nullptr;
std::unique_ptr<HistoryView::Element> _view;
};
} // namespace EditedLog

View file

@ -0,0 +1,370 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ayu/ui/sections/edited/edited_log_section.h"
#include "ayu/ui/sections/edited/edited_log_inner.h"
#include "profile/profile_back_button.h"
#include "core/shortcuts.h"
#include "ui/effects/animations.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/ui_utility.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "apiwrap.h"
#include "window/themes/window_theme.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "ui/boxes/confirm_box.h"
#include "base/timer.h"
#include "data/data_channel.h"
#include "data/data_session.h"
#include "lang/lang_keys.h"
#include "styles/style_chat.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_window.h"
#include "styles/style_info.h"
namespace EditedLog
{
class FixedBar final : public TWidget
{
public:
FixedBar(
QWidget *parent,
not_null<Window::SessionController *> controller,
not_null<PeerData *> peer);
// When animating mode is enabled the content is hidden and the
// whole fixed bar acts like a back button.
void setAnimatingMode(bool enabled);
void goBack();
protected:
void mousePressEvent(QMouseEvent *e) override;
void paintEvent(QPaintEvent *e) override;
int resizeGetHeight(int newWidth) override;
private:
not_null<Window::SessionController *> _controller;
not_null<PeerData *> _peer;
object_ptr<Profile::BackButton> _backButton;
object_ptr<Ui::CrossButton> _cancel;
bool _animatingMode = false;
};
object_ptr<Window::SectionWidget> SectionMemento::createWidget(
QWidget *parent,
not_null<Window::SessionController *> controller,
Window::Column column,
const QRect &geometry)
{
if (column == Window::Column::Third) {
return nullptr;
}
auto result = object_ptr<Widget>(parent, controller, _peer, _item);
result->setInternalState(geometry, this);
return result;
}
FixedBar::FixedBar(
QWidget *parent,
not_null<Window::SessionController *> controller,
not_null<PeerData *> peer)
: TWidget(parent), _controller(controller), _peer(peer), _backButton(
this,
&controller->session(),
tr::lng_admin_log_title_all(tr::now),
controller->adaptive().oneColumnValue()), _cancel(this, st::historyAdminLogCancelSearch)
{
_backButton->moveToLeft(0, 0);
_backButton->setClickedCallback([=]
{ goBack(); });
_cancel->hide(anim::type::instant);
}
void FixedBar::goBack()
{
_controller->showBackFromStack();
}
int FixedBar::resizeGetHeight(int newWidth)
{
auto filterLeft = newWidth;
auto cancelLeft = filterLeft - _cancel->width();
_cancel->moveToLeft(cancelLeft, 0);
auto searchShownLeft = st::topBarArrowPadding.left();
auto searchHiddenLeft = filterLeft - 0;
auto searchCurrentLeft = anim::interpolate(searchHiddenLeft, searchShownLeft, 0.0);
_backButton->resizeToWidth(searchCurrentLeft);
_backButton->moveToLeft(0, 0);
auto newHeight = _backButton->height();
return newHeight;
}
void FixedBar::setAnimatingMode(bool enabled)
{
if (_animatingMode != enabled) {
_animatingMode = enabled;
setCursor(_animatingMode ? style::cur_pointer : style::cur_default);
if (_animatingMode) {
setAttribute(Qt::WA_OpaquePaintEvent, false);
hideChildren();
}
else {
setAttribute(Qt::WA_OpaquePaintEvent);
showChildren();
_cancel->setVisible(false);
}
show();
}
}
void FixedBar::paintEvent(QPaintEvent *e)
{
if (!_animatingMode) {
auto p = QPainter(this);
p.fillRect(e->rect(), st::topBarBg);
}
}
void FixedBar::mousePressEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton) {
goBack();
}
else {
TWidget::mousePressEvent(e);
}
}
Widget::Widget(
QWidget *parent,
not_null<Window::SessionController *> controller,
not_null<PeerData *> peer,
not_null<HistoryItem *> item)
: Window::SectionWidget(parent, controller, rpl::single<PeerData *>(peer)),
_scroll(this, st::historyScroll, false),
_fixedBar(this, controller, peer),
_fixedBarShadow(this),
_whatIsThis(
this,
tr::lng_admin_log_about(tr::now),
st::historyComposeButton),
_item(item)
{
_fixedBar->move(0, 0);
_fixedBar->resizeToWidth(width());
_fixedBar->show();
_fixedBarShadow->raise();
controller->adaptive().value(
) | rpl::start_with_next([=]
{
updateAdaptiveLayout();
}, lifetime());
_inner = _scroll->setOwnedWidget(object_ptr<InnerWidget>(this, controller, peer, item));
_inner->scrollToSignal(
) | rpl::start_with_next([=](int top)
{
_scroll->scrollToY(top);
}, lifetime());
_scroll->move(0, _fixedBar->height());
_scroll->show();
_scroll->scrolls(
) | rpl::start_with_next([=]
{
onScroll();
}, lifetime());
_whatIsThis->setClickedCallback([=]
{
controller->show(Ui::MakeInformBox(peer->isMegagroup()
? tr::lng_admin_log_about_text()
: tr::lng_admin_log_about_text_channel()));
});
setupShortcuts();
}
void Widget::updateAdaptiveLayout()
{
_fixedBarShadow->moveToLeft(
controller()->adaptive().isOneColumn()
? 0
: st::lineWidth,
_fixedBar->height());
}
not_null<PeerData *> Widget::channel() const
{
return _inner->channel();
}
Dialogs::RowDescriptor Widget::activeChat() const
{
return {
channel()->owner().history(channel()),
FullMsgId(channel()->id, ShowAtUnreadMsgId)
};
}
QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams &params)
{
if (params.withTopBarShadow) _fixedBarShadow->hide();
auto result = Ui::GrabWidget(this);
if (params.withTopBarShadow) _fixedBarShadow->show();
return result;
}
void Widget::doSetInnerFocus()
{
_inner->setFocus();
}
bool Widget::showInternal(
not_null<Window::SectionMemento *> memento,
const Window::SectionShow &params)
{
if (auto logMemento = dynamic_cast<SectionMemento *>(memento.get())) {
if (logMemento->getPeer() == channel()) {
restoreState(logMemento);
return true;
}
}
return false;
}
void Widget::setInternalState(const QRect &geometry, not_null<SectionMemento *> memento)
{
setGeometry(geometry);
Ui::SendPendingMoveResizeEvents(this);
restoreState(memento);
}
void Widget::setupShortcuts()
{
// todo: smth
}
std::shared_ptr<Window::SectionMemento> Widget::createMemento()
{
auto result = std::make_shared<SectionMemento>(channel(), _item);
saveState(result.get());
return result;
}
void Widget::saveState(not_null<SectionMemento *> memento)
{
memento->setScrollTop(_scroll->scrollTop());
_inner->saveState(memento);
}
void Widget::restoreState(not_null<SectionMemento *> memento)
{
_inner->restoreState(memento);
auto scrollTop = memento->getScrollTop();
_scroll->scrollToY(scrollTop);
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
}
void Widget::resizeEvent(QResizeEvent *e)
{
if (!width() || !height()) {
return;
}
auto contentWidth = width();
auto newScrollTop = _scroll->scrollTop() + topDelta();
_fixedBar->resizeToWidth(contentWidth);
_fixedBarShadow->resize(contentWidth, st::lineWidth);
auto bottom = height();
auto scrollHeight = bottom - _fixedBar->height() - _whatIsThis->height();
auto scrollSize = QSize(contentWidth, scrollHeight);
if (_scroll->size() != scrollSize) {
_scroll->resize(scrollSize);
_inner->resizeToWidth(scrollSize.width(), _scroll->height());
_inner->restoreScrollPosition();
}
if (!_scroll->isHidden()) {
if (topDelta()) {
_scroll->scrollToY(newScrollTop);
}
auto scrollTop = _scroll->scrollTop();
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
}
auto fullWidthButtonRect = myrtlrect(0, bottom - _whatIsThis->height(), contentWidth, _whatIsThis->height());
_whatIsThis->setGeometry(fullWidthButtonRect);
}
void Widget::paintEvent(QPaintEvent *e)
{
if (animatingShow()) {
SectionWidget::paintEvent(e);
return;
}
else if (controller()->contentOverlapped(this, e)) {
return;
}
//if (hasPendingResizedItems()) {
// updateListSize();
//}
//auto ms = crl::now();
//_historyDownShown.step(ms);
const auto clip = e->rect();
SectionWidget::PaintBackground(controller(), _inner->theme(), this, clip);
}
void Widget::onScroll()
{
int scrollTop = _scroll->scrollTop();
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
}
void Widget::showAnimatedHook(
const Window::SectionSlideParams &params)
{
_fixedBar->setAnimatingMode(true);
if (params.withTopBarShadow) _fixedBarShadow->show();
}
void Widget::showFinishedHook()
{
_fixedBar->setAnimatingMode(false);
}
bool Widget::floatPlayerHandleWheelEvent(QEvent *e)
{
return _scroll->viewportEvent(e);
}
QRect Widget::floatPlayerAvailableRect()
{
return mapToGlobal(_scroll->geometry());
}
} // namespace EditedLog

View file

@ -0,0 +1,159 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "window/section_widget.h"
#include "window/section_memento.h"
#include "ayu/ui/sections/edited/edited_log_item.h"
#include "mtproto/sender.h"
namespace Ui
{
class ScrollArea;
class PlainShadow;
class FlatButton;
} // namespace Ui
namespace Profile
{
class BackButton;
} // namespace Profile
namespace EditedLog
{
class FixedBar;
class InnerWidget;
class SectionMemento;
class Widget final : public Window::SectionWidget
{
public:
Widget(
QWidget *parent,
not_null<Window::SessionController *> controller,
not_null<PeerData *> peer,
not_null<HistoryItem *> item);
not_null<PeerData *> channel() const;
Dialogs::RowDescriptor activeChat() const override;
bool hasTopBarShadow() const override
{
return true;
}
QPixmap grabForShowAnimation(const Window::SectionSlideParams &params) override;
bool showInternal(
not_null<Window::SectionMemento *> memento,
const Window::SectionShow &params) override;
std::shared_ptr<Window::SectionMemento> createMemento() override;
void setInternalState(const QRect &geometry, not_null<SectionMemento *> memento);
// Float player interface.
bool floatPlayerHandleWheelEvent(QEvent *e) override;
QRect floatPlayerAvailableRect() override;
protected:
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void showAnimatedHook(
const Window::SectionSlideParams &params) override;
void showFinishedHook() override;
void doSetInnerFocus() override;
private:
void onScroll();
void updateAdaptiveLayout();
void saveState(not_null<SectionMemento *> memento);
void restoreState(not_null<SectionMemento *> memento);
void setupShortcuts();
object_ptr<Ui::ScrollArea> _scroll;
QPointer<InnerWidget> _inner;
object_ptr<FixedBar> _fixedBar;
object_ptr<Ui::PlainShadow> _fixedBarShadow;
object_ptr<Ui::FlatButton> _whatIsThis;
not_null<HistoryItem *> _item;
};
class SectionMemento : public Window::SectionMemento
{
public:
using Element = HistoryView::Element;
SectionMemento(not_null<PeerData *> peer, not_null<HistoryItem *> item)
: _peer(peer),
_item(item)
{
}
object_ptr<Window::SectionWidget> createWidget(
QWidget *parent,
not_null<Window::SessionController *> controller,
Window::Column column,
const QRect &geometry) override;
not_null<PeerData *> getPeer() const
{
return _peer;
}
void setScrollTop(int scrollTop)
{
_scrollTop = scrollTop;
}
int getScrollTop() const
{
return _scrollTop;
}
void setItems(
std::vector<OwnedItem> &&items,
std::set<uint64> &&eventIds,
bool upLoaded,
bool downLoaded)
{
_items = std::move(items);
_eventIds = std::move(eventIds);
_upLoaded = upLoaded;
_downLoaded = downLoaded;
}
std::vector<OwnedItem> takeItems()
{
return std::move(_items);
}
std::set<uint64> takeEventIds()
{
return std::move(_eventIds);
}
bool upLoaded() const
{
return _upLoaded;
}
bool downLoaded() const
{
return _downLoaded;
}
private:
not_null<PeerData *> _peer;
not_null<HistoryItem *> _item;
int _scrollTop = 0;
std::vector<not_null<UserData *>> _admins;
std::vector<not_null<UserData *>> _adminsCanEdit;
std::vector<OwnedItem> _items;
std::set<uint64> _eventIds;
bool _upLoaded = false;
bool _downLoaded = true;
};
} // namespace EditedLog

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#include "icon_picker.h"
#include "ayu/ayu_settings.h"
#include "core/application.h"
@ -21,10 +20,9 @@
#include "ayu/utils/windows_utils.h"
#endif
void drawIcon(QPainter& p, const QImage& icon, int offset, bool selected)
void drawIcon(QPainter &p, const QImage &icon, int offset, bool selected)
{
if (selected)
{
if (selected) {
p.save();
p.setPen(QPen(st::iconPreviewStroke, 2));
p.drawEllipse(offset + 2, 2, 68, 68);
@ -35,12 +33,13 @@ void drawIcon(QPainter& p, const QImage& icon, int offset, bool selected)
p.drawImage(rect, icon);
}
IconPicker::IconPicker(QWidget* parent) : RpWidget(parent)
IconPicker::IconPicker(QWidget *parent)
: RpWidget(parent)
{
setMinimumSize(st::boxWidth, 72);
}
void IconPicker::paintEvent(QPaintEvent* e)
void IconPicker::paintEvent(QPaintEvent *e)
{
Painter p(this);
PainterHighQualityEnabler hq(p);
@ -55,30 +54,26 @@ void IconPicker::paintEvent(QPaintEvent* e)
drawIcon(p, icon3, 0 + 64 + 16 + 64 + 16, currentAppLogoName() == AyuSettings::NOTHING_ICON);
}
void IconPicker::mousePressEvent(QMouseEvent* e)
void IconPicker::mousePressEvent(QMouseEvent *e)
{
auto settings = &AyuSettings::getInstance();
auto changed = false;
auto x = e->pos().x();
if (x <= 64 && settings->appIcon != AyuSettings::DEFAULT_ICON)
{
if (x <= 64 && settings->appIcon != AyuSettings::DEFAULT_ICON) {
settings->set_appIcon(AyuSettings::DEFAULT_ICON);
changed = true;
}
else if (x >= 64 + 16 && x <= 64 + 16 + 64 && settings->appIcon != AyuSettings::ALT_ICON)
{
else if (x >= 64 + 16 && x <= 64 + 16 + 64 && settings->appIcon != AyuSettings::ALT_ICON) {
settings->set_appIcon(AyuSettings::ALT_ICON);
changed = true;
}
else if (x >= 64 + 16 + 64 + 16 && x < 64 + 16 + 64 + 16 + 64 && settings->appIcon != AyuSettings::NOTHING_ICON)
{
else if (x >= 64 + 16 + 64 + 16 && x < 64 + 16 + 64 + 16 + 64 && settings->appIcon != AyuSettings::NOTHING_ICON) {
settings->set_appIcon(AyuSettings::NOTHING_ICON);
changed = true;
}
if (changed)
{
if (changed) {
AyuSettings::save();
#ifdef Q_OS_WIN

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "ui/rp_widget.h"
@ -12,9 +11,9 @@
class IconPicker : public Ui::RpWidget
{
public:
IconPicker(QWidget* parent);
IconPicker(QWidget *parent);
protected:
void paintEvent(QPaintEvent* e) override;
void mousePressEvent(QMouseEvent* e) override;
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
};

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "base/options.h"
@ -14,54 +13,56 @@ class BoxContent;
namespace Window
{
class Controller;
class SessionController;
class Controller;
class SessionController;
} // namespace Window
extern const char kStreamerMode[];
extern base::options::toggle StreamerMode;
namespace Settings
{
class Ayu : public Section<Ayu>
{
public:
Ayu(QWidget* parent, not_null<Window::SessionController*> controller);
[[nodiscard]] rpl::producer<QString> title() override;
class Ayu : public Section<Ayu>
{
public:
Ayu(QWidget *parent, not_null<Window::SessionController *> controller);
private:
void AddPlatformOption(
not_null<Window::SessionController*> window,
not_null<Ui::VerticalLayout*> container,
base::options::option<bool>& option,
rpl::producer<> resetClicks);
[[nodiscard]] rpl::producer<QString> title() override;
void SetupGhostEssentials(not_null<Ui::VerticalLayout*> container);
private:
void AddPlatformOption(
not_null<Window::SessionController *> window,
not_null<Ui::VerticalLayout *> container,
base::options::option<bool> &option,
rpl::producer<> resetClicks);
void SetupSpyEssentials(not_null<Ui::VerticalLayout*> container);
void SetupGhostEssentials(not_null<Ui::VerticalLayout *> container);
void SetupQoLToggles(not_null<Ui::VerticalLayout*> container);
void SetupSpyEssentials(not_null<Ui::VerticalLayout *> container);
void SetupAppIcon(not_null<Ui::VerticalLayout*> container);
void SetupQoLToggles(not_null<Ui::VerticalLayout *> container);
void SetupCustomization(not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller);
void SetupAppIcon(not_null<Ui::VerticalLayout *> container);
void SetupShowPeerId(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller);
void SetupCustomization(not_null<Ui::VerticalLayout *> container,
not_null<Window::SessionController *> controller);
void SetupRecentStickersLimitSlider(not_null<Ui::VerticalLayout*> container);
void SetupShowPeerId(not_null<Ui::VerticalLayout *> container, not_null<Window::SessionController *> controller);
void SetupAyuSync(not_null<Ui::VerticalLayout*> container);
void SetupRecentStickersLimitSlider(not_null<Ui::VerticalLayout *> container);
void SetupSendConfirmations(not_null<Ui::VerticalLayout*> container);
void SetupAyuSync(not_null<Ui::VerticalLayout *> container);
void SetupExperimental(not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller);
void SetupSendConfirmations(not_null<Ui::VerticalLayout *> container);
void SetupAyuGramSettings(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> null);
void SetupExperimental(not_null<Ui::VerticalLayout *> container,
not_null<Window::SessionController *> controller);
void SetupAyuGramSettings(not_null<Ui::VerticalLayout *> container, not_null<Window::SessionController *> null);
void setupContent(not_null<Window::SessionController *> controller);
};
void setupContent(not_null<Window::SessionController*> controller);
};
} // namespace Settings

View file

@ -13,26 +13,22 @@
constexpr auto kMaxChannelId = -1000000000000;
QString IDString(not_null<PeerData*> peer)
QString IDString(not_null<PeerData *> peer)
{
auto resultId = QString::number(peerIsUser(peer->id)
? peerToUser(peer->id).bare
: peerIsChat(peer->id)
? peerToChat(peer->id).bare
: peerIsChannel(peer->id)
? peerToChannel(peer->id).bare
: peer->id.value);
? peerToUser(peer->id).bare
: peerIsChat(peer->id)
? peerToChat(peer->id).bare
: peerIsChannel(peer->id)
? peerToChannel(peer->id).bare
: peer->id.value);
const auto settings = &AyuSettings::getInstance();
if (settings->showPeerId == 2)
{
if (peer->isChannel())
{
if (settings->showPeerId == 2) {
if (peer->isChannel()) {
resultId = QString::number(peerToChannel(peer->id).bare - kMaxChannelId).prepend("-");
}
else if (peer->isChat())
{
else if (peer->isChat()) {
resultId = resultId.prepend("-");
}
}
@ -47,8 +43,7 @@ QString IDString(MsgId topic_root_id)
return resultId;
}
rpl::producer<TextWithEntities> IDValue(not_null<PeerData*> peer)
rpl::producer<TextWithEntities> IDValue(not_null<PeerData *> peer)
{
return rpl::single(IDString(peer)) | Ui::Text::ToWithEntities();
}

View file

@ -4,12 +4,11 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
QString IDString(not_null<PeerData*> peer);
QString IDString(not_null<PeerData *> peer);
QString IDString(MsgId topic_root_id);
rpl::producer<TextWithEntities> IDValue(not_null<PeerData*> peer);
rpl::producer<TextWithEntities> IDValue(not_null<PeerData *> peer);
rpl::producer<TextWithEntities> IDValue(MsgId topicRootId);

View file

@ -0,0 +1,86 @@
// This is the source code of AyuGram for Desktop.
//
// We do not and cannot prevent the use of our code,
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#include "ayu_mapper.h"
#include "history/history_item.h"
#include "history/history_item_components.h"
#include "history/history.h"
namespace AyuMapper
{
int mapItemFlagsToMTPFlags(not_null<HistoryItem *> item) {
int flags = 0;
const auto thread = item->topic()
? (Data::Thread*)item->topic()
: item->history();
const auto unseen = item->unread(thread);
if (unseen) {
flags |= 1;
}
if (item->out()) {
flags |= 2;
}
if (const auto reply = item->Get<HistoryMessageForwarded>()) {
flags |= 4;
}
if (const auto reply = item->Get<HistoryMessageReply>()) {
flags |= 8;
}
if (item->mentionsMe()) {
flags |= 16;
}
if (item->isUnreadMedia()) {
flags |= 32;
}
if (item->isSilent()) {
flags |= 8192;
}
if (item->isPost()) {
flags |= 16384;
}
if (item->isScheduled()) {
flags |= 262144;
}
// todo: legacy
// if (item->isLegacy()) {
// flags |= 524288;
// }
if (item->hideEditedBadge()) {
flags |= 2097152;
}
if (item->isPinned()) {
flags |= 16777216;
}
if (item->forbidsForward()) {
flags |= 67108864;
}
if (item->topic() && item->topicRootId() == item->id) {
flags |= 134217728;
}
return flags;
}
}

View file

@ -0,0 +1,14 @@
// This is the source code of AyuGram for Desktop.
//
// We do not and cannot prevent the use of our code,
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
namespace AyuMapper
{
int mapItemFlagsToMTPFlags(not_null<HistoryItem *> item);
} // namespace AyuMapper

View file

@ -20,14 +20,11 @@
#include "history/history_item.h"
Main::Session* getSession(ID userId)
Main::Session *getSession(ID userId)
{
for (const auto& [index, account] : Core::App().domain().accounts())
{
if (const auto session = account->maybeSession())
{
if (session->userId().bare == userId)
{
for (const auto &[index, account] : Core::App().domain().accounts()) {
if (const auto session = account->maybeSession()) {
if (session->userId().bare == userId) {
return session;
}
}
@ -54,62 +51,56 @@ void dispatchToMainThread(std::function<void()> callback)
QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0));
}
not_null<History*> getHistoryFromDialogId(ID dialogId, Main::Session* session)
not_null<History *> getHistoryFromDialogId(ID dialogId, Main::Session *session)
{
if (dialogId > 0)
{
if (dialogId > 0) {
return session->data().history(peerFromUser(dialogId));
}
auto history = session->data().history(peerFromChannel(abs(dialogId)));
if (history->folderKnown())
{
if (history->folderKnown()) {
return history;
}
return session->data().history(peerFromChat(abs(dialogId)));
}
ID getDialogIdFromPeer(not_null<PeerData*> peer)
ID getDialogIdFromPeer(not_null<PeerData *> peer)
{
auto peerId = peerIsUser(peer->id)
? peerToUser(peer->id).bare
: peerIsChat(peer->id)
? peerToChat(peer->id).bare
: peerIsChannel(peer->id)
? peerToChannel(peer->id).bare
: peer->id.value;
? peerToUser(peer->id).bare
: peerIsChat(peer->id)
? peerToChat(peer->id).bare
: peerIsChannel(peer->id)
? peerToChannel(peer->id).bare
: peer->id.value;
if (peer->isChannel() || peer->isChat())
{
if (peer->isChannel() || peer->isChat()) {
peerId = -peerId;
}
return peerId;
}
std::pair<std::string, std::string> serializeTextWithEntities(not_null<HistoryItem*> item)
std::pair<std::string, std::string> serializeTextWithEntities(not_null<HistoryItem *> item)
{
if (item->emptyText())
{
if (item->emptyText()) {
return std::make_pair("", "");
}
auto textWithEntities = item->originalText();
auto text = textWithEntities.text.toStdString();
auto entities = EntitiesToMTP(&item->history()->owner().session(), textWithEntities.entities,
Api::ConvertOption::SkipLocal);
Api::ConvertOption::SkipLocal);
if (entities.v.isEmpty())
{
if (entities.v.isEmpty()) {
return std::make_pair(text, "");
}
auto buff = mtpBuffer();
for (auto entity : entities.v)
{
for (auto entity : entities.v) {
entity.write(buff);
}
return std::make_pair(text, std::string(reinterpret_cast<char*>(buff.data()), buff.size()));
return std::make_pair(text, std::string(reinterpret_cast<char *>(buff.data()), buff.size()));
}

View file

@ -4,7 +4,6 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2023
#pragma once
#include "ayu/sync/models.h"
@ -14,9 +13,9 @@
#include "main/main_domain.h"
#include "main/main_session.h"
Main::Session* getSession(ID userId);
Main::Session *getSession(ID userId);
bool accountExists(ID userId);
void dispatchToMainThread(std::function<void()> callback);
not_null<History*> getHistoryFromDialogId(ID dialogId, Main::Session* session);
ID getDialogIdFromPeer(not_null<PeerData*> peer);
std::pair<std::string, std::string> serializeTextWithEntities(not_null<HistoryItem*> item);
not_null<History *> getHistoryFromDialogId(ID dialogId, Main::Session *session);
ID getDialogIdFromPeer(not_null<PeerData *> peer);
std::pair<std::string, std::string> serializeTextWithEntities(not_null<HistoryItem *> item);

View file

@ -10,7 +10,8 @@
#include <ShlObj_core.h>
void reloadAppIconFromTaskBar() {
void reloadAppIconFromTaskBar()
{
QString appdata = QDir::fromNativeSeparators(qgetenv("APPDATA"));
QString ayugramIconPath = appdata + "/AyuGram.ico";
@ -24,9 +25,9 @@ void reloadAppIconFromTaskBar() {
IPersistFile *pPersistFile = NULL;
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
(void **) &pShellLink);
(void **)&pShellLink);
if (SUCCEEDED(hr)) {
hr = pShellLink->QueryInterface(IID_IPersistFile, (void **) &pPersistFile);
hr = pShellLink->QueryInterface(IID_IPersistFile, (void **)&pPersistFile);
if (SUCCEEDED(hr)) {
WCHAR wszShortcutPath[MAX_PATH];
shortcut.toWCharArray(wszShortcutPath);

View file

@ -80,6 +80,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ayu/database/ayu_database.h"
#include "ayu/messages/ayu_messages_controller.h"
#include "ayu/ui/boxes/message_history_box.h"
#include "ayu/ui/sections/edited/edited_log_section.h"
namespace HistoryView {
namespace {
@ -1091,8 +1092,7 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
{
result->addAction(tr::ayu_EditsHistoryMenuText(tr::now), [=]
{
auto box = Box<AyuUi::MessageHistoryBox>(item);
Ui::show(std::move(box));
item->history()->session().tryResolveWindow()->showSection(std::make_shared<EditedLog::SectionMemento>(item->history()->peer, item));
}, &st::menuIconInfo);
}