forked from Green-Sky/tomato
add tox avatar handling + prio png for paste + other fixes and updates
This commit is contained in:
parent
e7095a1849
commit
c79068c561
2
external/solanaceae_contact
vendored
2
external/solanaceae_contact
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 738d2abe7b4d6088412e56b89f4e26aab1a8bdba
|
Subproject commit 5ff7d1cee0c3ed22f9fe7d66021d95ad1c5a3f04
|
2
external/solanaceae_message3
vendored
2
external/solanaceae_message3
vendored
@ -1 +1 @@
|
|||||||
Subproject commit c577a1fa3d19272d481a0ed4a5b8715524204928
|
Subproject commit 48fb5f0889404370006ae12b3637a77d7d4ba485
|
2
external/solanaceae_tox
vendored
2
external/solanaceae_tox
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 0e6556cd86c558c86dfde60d82891a46bf32b64f
|
Subproject commit 0404ed84fcc31716918b90b3603c722a73e908cb
|
@ -37,6 +37,9 @@ add_executable(tomato
|
|||||||
./message_image_loader.hpp
|
./message_image_loader.hpp
|
||||||
./message_image_loader.cpp
|
./message_image_loader.cpp
|
||||||
|
|
||||||
|
./tox_avatar_manager.hpp
|
||||||
|
./tox_avatar_manager.cpp
|
||||||
|
|
||||||
./media_meta_info_loader.hpp
|
./media_meta_info_loader.hpp
|
||||||
./media_meta_info_loader.cpp
|
./media_meta_info_loader.cpp
|
||||||
|
|
||||||
|
@ -374,8 +374,8 @@ void ChatGui4::render(void) {
|
|||||||
//} else if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
//} else if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||||
} else if (ImGui::BeginPopupContextItem(nullptr, ImGuiMouseButton_Right)) {
|
} else if (ImGui::BeginPopupContextItem(nullptr, ImGuiMouseButton_Right)) {
|
||||||
const static std::vector<const char*> image_mime_types {
|
const static std::vector<const char*> image_mime_types {
|
||||||
"image/webp",
|
|
||||||
"image/png",
|
"image/png",
|
||||||
|
"image/webp",
|
||||||
"image/gif",
|
"image/gif",
|
||||||
"image/jpeg",
|
"image/jpeg",
|
||||||
"image/bmp",
|
"image/bmp",
|
||||||
@ -459,6 +459,12 @@ void ChatGui4::renderMessageBodyText(Message3Registry& reg, const Message3 e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
|
void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
|
||||||
|
if (reg.all_of<Message::Components::Transfer::FileKind>(e) && reg.get<Message::Components::Transfer::FileKind>(e).kind == 1) {
|
||||||
|
// TODO: this looks ugly
|
||||||
|
ImGui::TextDisabled("set avatar");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (msg_reg.all_of<Components::TransferState>(e)) {
|
if (msg_reg.all_of<Components::TransferState>(e)) {
|
||||||
switch (msg_reg.get<Components::TransferState>(e).state) {
|
switch (msg_reg.get<Components::TransferState>(e).state) {
|
||||||
|
@ -16,6 +16,7 @@ MainScreen::MainScreen(SDL_Renderer* renderer_, std::string save_path, std::stri
|
|||||||
tmm(rmm, cr, tcm, tc, tc),
|
tmm(rmm, cr, tcm, tc, tc),
|
||||||
ttm(rmm, cr, tcm, tc, tc),
|
ttm(rmm, cr, tcm, tc, tc),
|
||||||
mmil(rmm),
|
mmil(rmm),
|
||||||
|
tam(rmm, cr, conf),
|
||||||
sdlrtu(renderer_),
|
sdlrtu(renderer_),
|
||||||
cg(conf, rmm, cr, sdlrtu)
|
cg(conf, rmm, cr, sdlrtu)
|
||||||
{
|
{
|
||||||
@ -78,6 +79,8 @@ Screen* MainScreen::poll(bool& quit) {
|
|||||||
|
|
||||||
tcm.iterate(time_delta);
|
tcm.iterate(time_delta);
|
||||||
|
|
||||||
|
tam.iterate();
|
||||||
|
|
||||||
pm.tick(time_delta);
|
pm.tick(time_delta);
|
||||||
|
|
||||||
mts.iterate();
|
mts.iterate();
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "./auto_dirty.hpp"
|
#include "./auto_dirty.hpp"
|
||||||
|
|
||||||
#include "./media_meta_info_loader.hpp"
|
#include "./media_meta_info_loader.hpp"
|
||||||
|
#include "./tox_avatar_manager.hpp"
|
||||||
|
|
||||||
#include "./sdlrenderer_texture_uploader.hpp"
|
#include "./sdlrenderer_texture_uploader.hpp"
|
||||||
#include "./chat_gui4.hpp"
|
#include "./chat_gui4.hpp"
|
||||||
@ -50,6 +51,7 @@ struct MainScreen final : public Screen {
|
|||||||
ToxTransferManager ttm;
|
ToxTransferManager ttm;
|
||||||
|
|
||||||
MediaMetaInfoLoader mmil;
|
MediaMetaInfoLoader mmil;
|
||||||
|
ToxAvatarManager tam;
|
||||||
|
|
||||||
SDLRendererTextureUploader sdlrtu;
|
SDLRendererTextureUploader sdlrtu;
|
||||||
//OpenGLTextureUploader ogltu;
|
//OpenGLTextureUploader ogltu;
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
const char* clipboardHasImage(void) {
|
const char* clipboardHasImage(void) {
|
||||||
const static std::vector<const char*> image_mime_types {
|
const static std::vector<const char*> image_mime_types {
|
||||||
"image/webp",
|
|
||||||
"image/png",
|
"image/png",
|
||||||
|
"image/webp",
|
||||||
"image/gif",
|
"image/gif",
|
||||||
"image/jpeg",
|
"image/jpeg",
|
||||||
"image/bmp",
|
"image/bmp",
|
||||||
|
@ -151,9 +151,11 @@ struct TextureCache {
|
|||||||
|
|
||||||
void invalidate(const std::vector<KeyType>& to_purge) {
|
void invalidate(const std::vector<KeyType>& to_purge) {
|
||||||
for (const auto& key : to_purge) {
|
for (const auto& key : to_purge) {
|
||||||
|
if (_cache.count(key)) {
|
||||||
for (const auto& tex_id : _cache.at(key).textures) {
|
for (const auto& tex_id : _cache.at(key).textures) {
|
||||||
_tu.destroy(tex_id);
|
_tu.destroy(tex_id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_cache.erase(key);
|
_cache.erase(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
|
|||||||
return new_entry;
|
return new_entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // continues if loading img fails
|
||||||
|
|
||||||
if (!_cr.any_of<
|
if (!_cr.any_of<
|
||||||
Contact::Components::ToxFriendPersistent,
|
Contact::Components::ToxFriendPersistent,
|
||||||
|
213
src/tox_avatar_manager.cpp
Normal file
213
src/tox_avatar_manager.cpp
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
#include "./tox_avatar_manager.hpp"
|
||||||
|
|
||||||
|
#include <solanaceae/util/config_model.hpp>
|
||||||
|
|
||||||
|
#include <solanaceae/message3/components.hpp>
|
||||||
|
// for comp transfer tox filekind (TODO: generalize -> content system?)
|
||||||
|
#include <solanaceae/tox_messages/components.hpp>
|
||||||
|
|
||||||
|
#include <solanaceae/contact/components.hpp>
|
||||||
|
#include <solanaceae/tox_contacts/components.hpp>
|
||||||
|
|
||||||
|
#include <solanaceae/toxcore/utils.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// see https://github.com/Tox/Tox-Client-Standard/blob/master/user_identification/avatar.md
|
||||||
|
// see (old) https://github.com/Tox-Archive/Tox-STS/blob/master/STS.md#avatars
|
||||||
|
|
||||||
|
// https://youtu.be/_uuCLRqc9QA
|
||||||
|
|
||||||
|
namespace Components {
|
||||||
|
struct TagAvatarImageHandled {};
|
||||||
|
};
|
||||||
|
|
||||||
|
ToxAvatarManager::ToxAvatarManager(
|
||||||
|
RegistryMessageModel& rmm,
|
||||||
|
Contact3Registry& cr,
|
||||||
|
ConfigModelI& conf
|
||||||
|
) : _rmm(rmm), _cr(cr), _conf(conf) {
|
||||||
|
_rmm.subscribe(this, RegistryMessageModel_Event::message_construct);
|
||||||
|
_rmm.subscribe(this, RegistryMessageModel_Event::message_updated);
|
||||||
|
|
||||||
|
if (!_conf.has_string("ToxAvatarManager", "save_path")) {
|
||||||
|
// or on linux: $HOME/.config/tox/avatars/
|
||||||
|
_conf.set("ToxAvatarManager", "save_path", std::string_view{"tmp_avatar_dir"});
|
||||||
|
}
|
||||||
|
|
||||||
|
//_conf.set("TransferAutoAccept", "autoaccept_limit", int64_t(50l*1024l*1024l)); // sane default
|
||||||
|
|
||||||
|
const std::string_view avatar_save_path {_conf.get_string("ToxAvatarManager", "save_path").value()};
|
||||||
|
// make sure it exists
|
||||||
|
std::filesystem::create_directories(avatar_save_path);
|
||||||
|
|
||||||
|
{ // scan tox contacts for cached avatars
|
||||||
|
// old sts says pubkey.png
|
||||||
|
|
||||||
|
_cr.view<Contact::Components::ToxFriendPersistent>().each([this](auto c, const Contact::Components::ToxFriendPersistent& tox_pers) {
|
||||||
|
addAvatarFileToContact(c, tox_pers.key);
|
||||||
|
});
|
||||||
|
|
||||||
|
_cr.view<Contact::Components::ToxGroupPersistent>().each([this](auto c, const Contact::Components::ToxGroupPersistent& tox_pers) {
|
||||||
|
addAvatarFileToContact(c, tox_pers.chat_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: also for group peers?
|
||||||
|
// TODO: conf?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToxAvatarManager::iterate(void) {
|
||||||
|
// cancel queue
|
||||||
|
|
||||||
|
// accept queue
|
||||||
|
for (auto& [m, path] : _accept_queue) {
|
||||||
|
if (m.all_of<Message::Components::Transfer::ActionAccept>()) {
|
||||||
|
continue; // already accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
m.emplace<Message::Components::Transfer::ActionAccept>(path, true);
|
||||||
|
std::cout << "TAM: auto accepted transfer\n";
|
||||||
|
|
||||||
|
_rmm.throwEventUpdate(m);
|
||||||
|
}
|
||||||
|
_accept_queue.clear();
|
||||||
|
|
||||||
|
// - add message/content/transfer listener for onComplete
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToxAvatarManager::getAvatarPath(const ToxKey& key) const {
|
||||||
|
const std::string_view avatar_save_path {_conf.get_string("ToxAvatarManager", "save_path").value()};
|
||||||
|
const auto pub_key_string = bin2hex({key.data.cbegin(), key.data.cend()});
|
||||||
|
const auto file_path = std::filesystem::path(avatar_save_path) / (pub_key_string + ".png");
|
||||||
|
return file_path.u8string();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToxAvatarManager::addAvatarFileToContact(const Contact3 c, const ToxKey& key) {
|
||||||
|
//const std::string_view avatar_save_path {_conf.get_string("ToxAvatarManager", "save_path").value()};
|
||||||
|
//const auto pub_key_string = bin2hex({key.data.cbegin(), key.data.cend()});
|
||||||
|
//const auto file_path = std::filesystem::path(avatar_save_path) / (pub_key_string + ".png");
|
||||||
|
const auto file_path = getAvatarPath(key);
|
||||||
|
if (std::filesystem::is_regular_file(file_path)) {
|
||||||
|
// avatar file png file exists
|
||||||
|
_cr.emplace_or_replace<Contact::Components::AvatarFile>(c, file_path);
|
||||||
|
_cr.emplace_or_replace<Contact::Components::TagAvatarInvalidate>(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToxAvatarManager::clearAvatarFromContact(const Contact3 c) {
|
||||||
|
if (_cr.all_of<Contact::Components::AvatarFile>(c)) {
|
||||||
|
std::filesystem::remove(_cr.get<Contact::Components::AvatarFile>(c).file_path);
|
||||||
|
_cr.remove<Contact::Components::AvatarFile>(c);
|
||||||
|
_cr.emplace_or_replace<Contact::Components::TagAvatarInvalidate>(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToxAvatarManager::checkMsg(Message3Handle h) {
|
||||||
|
if (h.any_of<
|
||||||
|
Message::Components::Transfer::ActionAccept,
|
||||||
|
Components::TagAvatarImageHandled
|
||||||
|
>()) {
|
||||||
|
return; // already accepted or handled
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!h.any_of<
|
||||||
|
Message::Components::Transfer::TagPaused,
|
||||||
|
Message::Components::Transfer::TagHaveAll
|
||||||
|
>()) {
|
||||||
|
// we only handle unaccepted or finished
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!h.all_of<
|
||||||
|
Message::Components::Transfer::TagReceiving,
|
||||||
|
Message::Components::Transfer::FileInfo,
|
||||||
|
Message::Components::Transfer::FileKind,
|
||||||
|
Message::Components::ContactFrom // should always be there, just making sure
|
||||||
|
>()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TCS-2.2.11 (big list, should have been sub points ...)
|
||||||
|
|
||||||
|
if (h.get<Message::Components::Transfer::FileKind>().kind != 1) {
|
||||||
|
// not an avatar
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& file_info = h.get<Message::Components::Transfer::FileInfo>();
|
||||||
|
|
||||||
|
// TCS-2.2.4
|
||||||
|
if (file_info.total_size > 65536ul) {
|
||||||
|
// TODO: mark handled?
|
||||||
|
return; // too large
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto contact = h.get<Message::Components::ContactFrom>().c;
|
||||||
|
|
||||||
|
// TCS-2.2.10
|
||||||
|
if (file_info.file_list.empty() || file_info.file_list.front().file_name.empty() || file_info.total_size == 0) {
|
||||||
|
// reset
|
||||||
|
clearAvatarFromContact(contact);
|
||||||
|
// TODO: cancel
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!h.all_of<
|
||||||
|
Message::Components::Transfer::FileID
|
||||||
|
>()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string file_path;
|
||||||
|
if (_cr.all_of<Contact::Components::ToxFriendPersistent>(contact)) {
|
||||||
|
file_path = getAvatarPath(_cr.get<Contact::Components::ToxFriendPersistent>(contact).key);
|
||||||
|
} else if (_cr.all_of<Contact::Components::ToxGroupPersistent>(contact)) {
|
||||||
|
file_path = getAvatarPath(_cr.get<Contact::Components::ToxGroupPersistent>(contact).chat_id);
|
||||||
|
} else {
|
||||||
|
std::cerr << "TAM error: cant get toxkey for contact\n";
|
||||||
|
// TODO: mark handled?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h.all_of<Message::Components::Transfer::TagHaveAll>()) {
|
||||||
|
std::cout << "TAM: full avatar received\n";
|
||||||
|
|
||||||
|
if (_cr.all_of<Contact::Components::ToxFriendPersistent>(contact)) {
|
||||||
|
addAvatarFileToContact(contact, _cr.get<Contact::Components::ToxFriendPersistent>(contact).key);
|
||||||
|
} else if (_cr.all_of<Contact::Components::ToxGroupPersistent>(contact)) {
|
||||||
|
addAvatarFileToContact(contact, _cr.get<Contact::Components::ToxGroupPersistent>(contact).chat_id);
|
||||||
|
} else {
|
||||||
|
std::cerr << "TAM error: cant get toxkey for contact\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
h.emplace_or_replace<Components::TagAvatarImageHandled>();
|
||||||
|
} else {
|
||||||
|
const auto& supposed_file_hash = h.get<Message::Components::Transfer::FileID>().id;
|
||||||
|
|
||||||
|
// check file id for existing hash
|
||||||
|
if (std::filesystem::is_regular_file(file_path)) {
|
||||||
|
// load file
|
||||||
|
// hash file
|
||||||
|
//_t.toxHash();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not already on disk
|
||||||
|
_accept_queue.push_back(AcceptEntry{h, file_path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToxAvatarManager::onEvent(const Message::Events::MessageConstruct& e) {
|
||||||
|
checkMsg(e.e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToxAvatarManager::onEvent(const Message::Events::MessageUpdated& e) {
|
||||||
|
checkMsg(e.e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
42
src/tox_avatar_manager.hpp
Normal file
42
src/tox_avatar_manager.hpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "solanaceae/contact/contact_model3.hpp"
|
||||||
|
#include <solanaceae/message3/registry_message_model.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
// RIP fishy c=<
|
||||||
|
|
||||||
|
struct ConfigModelI;
|
||||||
|
struct ToxKey;
|
||||||
|
|
||||||
|
class ToxAvatarManager : public RegistryMessageModelEventI {
|
||||||
|
RegistryMessageModel& _rmm;
|
||||||
|
Contact3Registry& _cr;
|
||||||
|
ConfigModelI& _conf;
|
||||||
|
|
||||||
|
struct AcceptEntry {
|
||||||
|
Message3Handle m;
|
||||||
|
std::string file_path;
|
||||||
|
};
|
||||||
|
std::vector<AcceptEntry> _accept_queue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ToxAvatarManager(
|
||||||
|
RegistryMessageModel& rmm,
|
||||||
|
Contact3Registry& cr,
|
||||||
|
ConfigModelI& conf
|
||||||
|
);
|
||||||
|
|
||||||
|
void iterate(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string getAvatarPath(const ToxKey& key) const;
|
||||||
|
void addAvatarFileToContact(const Contact3 c, const ToxKey& key);
|
||||||
|
void clearAvatarFromContact(const Contact3 c);
|
||||||
|
void checkMsg(Message3Handle h);
|
||||||
|
|
||||||
|
protected: // mm
|
||||||
|
bool onEvent(const Message::Events::MessageConstruct& e) override;
|
||||||
|
bool onEvent(const Message::Events::MessageUpdated& e) override;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user