aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--css/style.css38
-rw-r--r--include/ChatMessage.hpp6
-rw-r--r--include/ChatWindow.hpp19
-rw-r--r--include/User.hpp13
-rw-r--r--include/Window.hpp2
-rw-r--r--src/ChatMessage.cpp6
-rw-r--r--src/ChatWindow.cpp89
-rw-r--r--src/Window.cpp39
8 files changed, 189 insertions, 23 deletions
diff --git a/css/style.css b/css/style.css
index c024481..bb40474 100644
--- a/css/style.css
+++ b/css/style.css
@@ -20,10 +20,38 @@ button {
background-color: #2f3136;
color: #f7f7f7;
border-style: none;
+ outline-style: none;
+ box-shadow: 0px 0px 0px transparent;
+ text-shadow: 0px 0px 0px transparent;
+}
+
+menu {
+ background-color: #36393e;
+ color: #f7f7f7;
+ border: 1px solid black;
+}
+
+.emoji {
+ background-color: #36393e;
+ color: #f7f7f7;
+ border: 1px solid black;
+}
+
+.emoji-picker {
+ background-color: #36393e;
+ color: #f7f7f7;
+ border: 1px solid black;
+}
+
+.emoji-picker entry {
+ background-color: #36393e;
+ color: #f7f7f7;
+ border: 1px solid black;
}
#side-panels separator {
border: 1px solid #2f3136;
+ background-color: #2f3136;
}
#top-bar {
@@ -48,6 +76,11 @@ button {
*/
}
+#left-panel separator {
+ border: 1px solid #36393e;
+ background-color: #36393e;
+}
+
#channels-title {
color: #f7f7f7;
font-weight: bold;
@@ -124,4 +157,9 @@ textview text {
.window-notification {
background-color: #aa3030;
+}
+
+.username-list-username {
+ color: #0fc0fc;
+ font-weight: bold;
} \ No newline at end of file
diff --git a/include/ChatMessage.hpp b/include/ChatMessage.hpp
index 0547557..271aa5f 100644
--- a/include/ChatMessage.hpp
+++ b/include/ChatMessage.hpp
@@ -1,16 +1,20 @@
#pragma once
+#include "types.hpp"
#include <gtkmm/grid.h>
#include <gtkmm/label.h>
namespace dchat
{
+ class User;
class ChatMessage : public Gtk::Grid
{
public:
- ChatMessage(const Glib::ustring &username, const Glib::ustring &text);
+ ChatMessage(const Glib::ustring &username, const Glib::ustring &text, uint32_t timestampSeconds, const User *user);
Gtk::Label username;
Gtk::Label text;
+ uint32_t timestampSeconds;
+ const User *user;
};
} \ No newline at end of file
diff --git a/include/ChatWindow.hpp b/include/ChatWindow.hpp
index b13046e..b10af2b 100644
--- a/include/ChatWindow.hpp
+++ b/include/ChatWindow.hpp
@@ -1,7 +1,8 @@
#pragma once
+#include "User.hpp"
#include <gtkmm/label.h>
-#include <gtkmm/button.h>
+#include <gtkmm/togglebutton.h>
#include <gtkmm/grid.h>
#include <gtkmm/entry.h>
#include <gtkmm/paned.h>
@@ -9,15 +10,23 @@
#include <gtkmm/stack.h>
#include <gtkmm/textview.h>
#include <odhtdb/Hash.hpp>
+#include <odhtdb/Signature.hpp>
namespace dchat
{
+ class ChatMessage;
+
class ChatWindow : public Gtk::Grid
{
public:
ChatWindow();
void addChannel(const odhtdb::Hash &nodeHash);
- void addLocalMessage(const odhtdb::Hash &channelId, Glib::ustring msg);
+ void addLocalMessage(const odhtdb::Hash &channelId, const odhtdb::Signature::PublicKey &userPublicKey, uint32_t timestampSeconds, Glib::ustring msg);
+ void addUser(const odhtdb::Signature::PublicKey &userPublicKey);
+ void setUserNickname(const odhtdb::Signature::PublicKey &userPublicKey, const Glib::ustring &name);
+
+ // Returns nullptr if user with @publicKey is not found
+ User* getUserByPublicKey(const odhtdb::Signature::PublicKey &publicKey) const;
private:
void setupTopBar();
void setupLeftPanel(Gtk::Paned *sidePanels);
@@ -27,6 +36,7 @@ namespace dchat
Gtk::Grid topbar;
Gtk::Entry topbarSearchBar;
Gtk::Grid leftPanelChannels;
+ Gtk::Grid leftPanelUsers;
Gtk::Label currentChannelTitle;
Gtk::ScrolledWindow chatArea;
Gtk::Grid chatAreaLayout;
@@ -34,11 +44,14 @@ namespace dchat
struct ChannelData
{
- Gtk::Button *button;
+ Gtk::ToggleButton *button;
int messageCount;
};
odhtdb::MapHash<ChannelData> channelDataById;
int channelCount;
+ std::vector<User*> users;
+
+ ChatMessage *lastMessage;
};
} \ No newline at end of file
diff --git a/include/User.hpp b/include/User.hpp
new file mode 100644
index 0000000..471a5cc
--- /dev/null
+++ b/include/User.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <glibmm/ustring.h>
+#include <odhtdb/Signature.hpp>
+
+namespace dchat
+{
+ struct User
+ {
+ const odhtdb::Signature::PublicKey publicKey;
+ Glib::ustring name;
+ };
+} \ No newline at end of file
diff --git a/include/Window.hpp b/include/Window.hpp
index 96197c6..29ec285 100644
--- a/include/Window.hpp
+++ b/include/Window.hpp
@@ -14,7 +14,7 @@ namespace dchat
public:
Window();
virtual ~Window();
- protected:
+ private:
std::unique_ptr<odhtdb::Database> database;
std::mutex databaseCallbackMutex;
Gtk::Stack stack;
diff --git a/src/ChatMessage.cpp b/src/ChatMessage.cpp
index 048bfca..db5fad2 100644
--- a/src/ChatMessage.cpp
+++ b/src/ChatMessage.cpp
@@ -2,9 +2,11 @@
namespace dchat
{
- ChatMessage::ChatMessage(const Glib::ustring &_username, const Glib::ustring &_text) :
+ ChatMessage::ChatMessage(const Glib::ustring &_username, const Glib::ustring &_text, uint32_t _timestampSeconds, const User *_user) :
username(_username),
- text(_text)
+ text(_text),
+ timestampSeconds(_timestampSeconds),
+ user(_user)
{
username.set_selectable(true);
username.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_START);
diff --git a/src/ChatWindow.cpp b/src/ChatWindow.cpp
index bebc644..b0bb696 100644
--- a/src/ChatWindow.cpp
+++ b/src/ChatWindow.cpp
@@ -5,8 +5,12 @@
namespace dchat
{
+ // Merge all messages that are written by the same user without interrupt within a timeframe
+ const int MERGE_MESSAGE_TIMESTAMP_DIFF_SEC = 60;
+
ChatWindow::ChatWindow() :
- channelCount(0)
+ channelCount(0),
+ lastMessage(nullptr)
{
setupTopBar();
@@ -66,15 +70,14 @@ namespace dchat
leftPanelChannels.attach(*channelsTitle, 0, 0, 1, 1);
////
- Gtk::Grid *leftPanelUsers = Gtk::manage(new Gtk::Grid());
- leftPanelUsers->set_vexpand(true);
- leftPanel->add2(*leftPanelUsers);
+ leftPanelUsers.set_vexpand(true);
+ leftPanel->add2(leftPanelUsers);
Gtk::Label *usersTitle = Gtk::manage(new Gtk::Label());
usersTitle->set_name("users-title");
usersTitle->set_text("Users");
usersTitle->set_halign(Gtk::ALIGN_START);
- leftPanelUsers->attach(*usersTitle, 0, 0, 1, 1);
+ leftPanelUsers.attach(*usersTitle, 0, 0, 1, 1);
}
void ChatWindow::setupMessageArea(Gtk::Grid *rightPanel)
@@ -102,8 +105,9 @@ namespace dchat
void ChatWindow::addChannel(const odhtdb::Hash &nodeHash)
{
assert(channelDataById.find(nodeHash) == channelDataById.end());
- printf("Added channel\n");
- Gtk::Button *channelButton = Gtk::manage(new Gtk::Button("Channel name"));
+ fprintf(stderr, "Added channel %s\n", nodeHash.toString().c_str());
+ Gtk::ToggleButton *channelButton = Gtk::manage(new Gtk::ToggleButton("Channel name"));
+ channelButton->set_active(true);
channelButton->get_style_context()->add_class("channel-button");
channelButton->set_hexpand(true);
channelButton->get_child()->set_halign(Gtk::ALIGN_START);
@@ -113,15 +117,82 @@ namespace dchat
channelDataById[nodeHash] = { channelButton, 0 };
}
- void ChatWindow::addLocalMessage(const odhtdb::Hash &channelId, Glib::ustring msg)
+ void ChatWindow::addLocalMessage(const odhtdb::Hash &channelId, const odhtdb::Signature::PublicKey &userPublicKey, uint32_t timestampSeconds, Glib::ustring msg)
{
auto it = channelDataById.find(channelId);
assert(it != channelDataById.end());
- ChatMessage *message = Gtk::manage(new ChatMessage("Arezu", msg));
+ User *user = getUserByPublicKey(userPublicKey);
+ if(!user)
+ {
+ fprintf(stderr, "Unable to add message to channel because the user %s doesn't exist in it\n", userPublicKey.toString().c_str());
+ return;
+ }
+
+ if(lastMessage && lastMessage->user->publicKey == userPublicKey)
+ {
+ int64_t msgTimeDiff = (int64_t)timestampSeconds - (int64_t)lastMessage->timestampSeconds;
+ if(msgTimeDiff <= MERGE_MESSAGE_TIMESTAMP_DIFF_SEC)
+ {
+ lastMessage->text.set_text(lastMessage->text.get_text() + "\n" + msg);
+ return;
+ }
+ }
+
+ ChatMessage *message = Gtk::manage(new ChatMessage(user->name, msg, timestampSeconds, user));
+ lastMessage = message;
message->set_valign(Gtk::Align::ALIGN_START);
message->set_hexpand(true);
message->show_all();
chatAreaLayout.attach(*message, 0, it->second.messageCount, 1, 1);
++it->second.messageCount;
}
+
+ void ChatWindow::addUser(const odhtdb::Signature::PublicKey &userPublicKey)
+ {
+ User *existingUser = getUserByPublicKey(userPublicKey);
+ if(existingUser)
+ {
+ fprintf(stderr, "ChatWindow::addUser: user %s was not added because the user has already been added\n", userPublicKey.toString().c_str());
+ return;
+ }
+
+ Gtk::Label *username = Gtk::manage(new Gtk::Label("NoName"));
+ username->set_halign(Gtk::ALIGN_START);
+ username->show();
+ username->get_style_context()->add_class("username-list-username");
+ leftPanelUsers.attach(*username, 0, 1 + users.size(), 1, 1);
+ users.push_back(new User { userPublicKey, "NoName" });
+ fprintf(stderr, "Added user %s\n", userPublicKey.toString().c_str());
+ }
+
+ void ChatWindow::setUserNickname(const odhtdb::Signature::PublicKey &userPublicKey, const Glib::ustring &name)
+ {
+ for(size_t i = 0; i < users.size(); ++i)
+ {
+ User *user = users[i];
+ if(user->publicKey == userPublicKey)
+ {
+ user->name = name;
+ Gtk::Widget *usernameLabel = leftPanelUsers.get_child_at(0, 1 + i);
+ assert(usernameLabel);
+ //assert(usernameLabel->get_type() == Gtk::Label::get_type());
+ static_cast<Gtk::Label*>(usernameLabel)->set_text(name);
+ fprintf(stderr, "Set nickname for user %s to %s\n", userPublicKey.toString().c_str(), name.c_str());
+ return;
+ }
+ }
+ fprintf(stderr, "ChatWindow::setUserNickname: user %s doesn't exist\n", userPublicKey.toString().c_str());
+ }
+
+ User* ChatWindow::getUserByPublicKey(const odhtdb::Signature::PublicKey &publicKey) const
+ {
+ for(User *user : users)
+ {
+ if(user->publicKey == publicKey)
+ {
+ return user;
+ }
+ }
+ return nullptr;
+ }
} \ No newline at end of file
diff --git a/src/Window.cpp b/src/Window.cpp
index 38c187e..72a3d9d 100644
--- a/src/Window.cpp
+++ b/src/Window.cpp
@@ -2,6 +2,7 @@
#include "../include/Cache.hpp"
#include "../include/ChannelDataType.hpp"
#include "../include/WindowNotification.hpp"
+#include <sibs/SafeDeserializer.hpp>
namespace dchat
{
@@ -11,6 +12,7 @@ namespace dchat
Gtk::Overlay *overlay = Gtk::manage(new Gtk::Overlay());
WindowNotification *windowNotification = Gtk::manage(new WindowNotification());
overlay->add_overlay(*windowNotification);
+ overlay->set_overlay_pass_through(*windowNotification);
overlay->add(stack);
add(*overlay);
@@ -54,6 +56,7 @@ namespace dchat
{
std::lock_guard<std::mutex> lock(databaseCallbackMutex);
chatWindow.addChannel(*request.nodeHash);
+ chatWindow.addUser(*request.creatorPublicKey);
};
callbackFuncs.addNodeCallbackFunc = [this](const odhtdb::DatabaseAddNodeRequest &request)
@@ -63,22 +66,44 @@ namespace dchat
return;
ChannelDataType channelDataType = (ChannelDataType)static_cast<const char*>(request.decryptedData.data)[0];
- switch(channelDataType)
+ try
{
- case ChannelDataType::ADD_MESSAGE:
+ switch(channelDataType)
{
- Glib::ustring msg((const char*)request.decryptedData.data + 1, request.decryptedData.size - 1);
- chatWindow.addLocalMessage(*request.nodeHash, std::move(msg));
- break;
+ case ChannelDataType::ADD_MESSAGE:
+ {
+ Glib::ustring msg((const char*)request.decryptedData.data + 1, request.decryptedData.size - 1);
+ uint32_t timestampSeconds = ntp::NtpTimestamp::fromCombined(request.timestamp).seconds;
+ chatWindow.addLocalMessage(*request.nodeHash, *request.creatorPublicKey, timestampSeconds, std::move(msg));
+ break;
+ }
+ case ChannelDataType::NICKNAME_CHANGE:
+ {
+ sibs::SafeDeserializer deserializer((const u8*)request.decryptedData.data + 1, request.decryptedData.size - 1);
+ u8 nameLength = deserializer.extract<u8>();
+ if(nameLength > 0)
+ {
+ std::string nickname;
+ nickname.resize(nameLength);
+ deserializer.extract((u8*)&nickname[0], nameLength);
+ chatWindow.setUserNickname(*request.creatorPublicKey, nickname);
+ }
+ break;
+ }
+ default:
+ break;
}
- default:
- break;
+ }
+ catch(std::exception &e)
+ {
+ fprintf(stderr, "Failed to process add node request, reason: %s\n", e.what());
}
};
callbackFuncs.addUserCallbackFunc = [this](const odhtdb::DatabaseAddUserRequest &request)
{
std::lock_guard<std::mutex> lock(databaseCallbackMutex);
+ chatWindow.addUser(*request.userToAddPublicKey);
};
fprintf(stderr, "Connecting...\n");