Set room topic/name through conversation view

If the user has permission to change a room's subject or name, they can
now edit the text views displaying them (toward the top of the window).
When enter is pressed, the changes will be sent to the protocol.

To do this, a BTextView subclass was added to libinterface
(splitting somewhat from SendTextView)― EnterTextView sends a message
containing the text to the given target when the user hits enter sans
modifiers.
This commit is contained in:
Jaidyn Ann 2021-07-29 22:00:01 -05:00
parent 909a68e595
commit 89ff195c8d
11 changed files with 176 additions and 76 deletions

View File

@ -222,6 +222,17 @@ Conversation::ImMessage(BMessage* msg)
RemoveUser(user); RemoveUser(user);
break; break;
} }
case IM_ROOM_ROLECHANGED:
{
BString user_id;
Role* role = _GetRole(msg);
if (msg->FindString("user_id", &user_id) != B_OK || role == NULL)
break;
SetRole(user_id, role);
GetView()->MessageReceived(msg);
break;
}
case IM_LOGS_RECEIVED: case IM_LOGS_RECEIVED:
default: default:
GetView()->MessageReceived(msg); GetView()->MessageReceived(msg);
@ -437,7 +448,6 @@ Conversation::SetRole(BString id, Role* role)
fRoles.RemoveItemFor(id); fRoles.RemoveItemFor(id);
delete oldRole; delete oldRole;
} }
fRoles.AddItem(id, role); fRoles.AddItem(id, role);
} }
@ -579,7 +589,7 @@ Conversation::_EnsureUser(BMessage* msg)
user = serverUser; user = serverUser;
GetView()->UpdateUserList(fUsers); GetView()->UpdateUserList(fUsers);
_CloneUserIcon(user); _AdoptUserIcon(user);
} }
// Not anywhere; create user // Not anywhere; create user
else if (user == NULL) { else if (user == NULL) {
@ -590,7 +600,7 @@ Conversation::_EnsureUser(BMessage* msg)
fUsers.AddItem(id, user); fUsers.AddItem(id, user);
GetView()->UpdateUserList(fUsers); GetView()->UpdateUserList(fUsers);
_CloneUserIcon(user); _AdoptUserIcon(user);
} }
if (name.IsEmpty() == false) { if (name.IsEmpty() == false) {
@ -601,8 +611,26 @@ Conversation::_EnsureUser(BMessage* msg)
} }
Role*
Conversation::_GetRole(BMessage* msg)
{
if (!msg)
return NULL;
BString title;
int32 perms;
int32 priority;
if (msg->FindString("role_title", &title) != B_OK
|| msg->FindInt32("role_perms", &perms) != B_OK
|| msg->FindInt32("role_priority", &priority) != B_OK)
return NULL;
return new Role(title, perms, priority);
}
void void
Conversation::_CloneUserIcon(User* user) Conversation::_AdoptUserIcon(User* user)
{ {
// If it's a one-on-one chat without custom icon, steal a user's // If it's a one-on-one chat without custom icon, steal a user's
if ((fUsers.CountItems() <= 2 && user->GetId() != GetOwnContact()->GetId()) if ((fUsers.CountItems() <= 2 && user->GetId() != GetOwnContact()->GetId())

View File

@ -85,7 +85,9 @@ private:
void _EnsureCachePath(); void _EnsureCachePath();
User* _EnsureUser(BMessage* msg); User* _EnsureUser(BMessage* msg);
void _CloneUserIcon(User* user); Role* _GetRole(BMessage* msg);
void _AdoptUserIcon(User* user);
void _SortConversationList(); void _SortConversationList();

View File

@ -388,14 +388,6 @@ Server::ImMessage(BMessage* msg)
SendProtocolMessage(msg); SendProtocolMessage(msg);
break; break;
} }
case IM_ROOM_CREATED:
case IM_ROOM_JOINED:
{
Conversation* chat = _EnsureConversation(msg);
if (chat != NULL)
chat->ImMessage(msg);
break;
}
case IM_ROOM_PARTICIPANTS: case IM_ROOM_PARTICIPANTS:
{ {
Conversation* chat = _EnsureConversation(msg); Conversation* chat = _EnsureConversation(msg);
@ -417,44 +409,28 @@ Server::ImMessage(BMessage* msg)
} }
break; break;
} }
case IM_MESSAGE_SENT:
case IM_MESSAGE_RECEIVED:
case IM_ROOM_JOINED:
case IM_ROOM_CREATED:
case IM_ROOM_METADATA:
case IM_ROOM_ROLECHANGED:
case IM_ROOM_PARTICIPANT_JOINED: case IM_ROOM_PARTICIPANT_JOINED:
case IM_ROOM_PARTICIPANT_LEFT: case IM_ROOM_PARTICIPANT_LEFT:
case IM_ROOM_PARTICIPANT_BANNED: case IM_ROOM_PARTICIPANT_BANNED:
case IM_ROOM_PARTICIPANT_KICKED: case IM_ROOM_PARTICIPANT_KICKED:
{
Conversation* chat = _EnsureConversation(msg);
if (chat == NULL)
break;
chat->ImMessage(msg);
break;
}
case IM_ROOM_METADATA:
{ {
Conversation* chat = _EnsureConversation(msg); Conversation* chat = _EnsureConversation(msg);
if (chat != NULL) if (chat != NULL)
chat->ImMessage(msg); chat->ImMessage(msg);
break; break;
} }
case IM_ROOM_ROLECHANGED:
{
Conversation* chat = _EnsureConversation(msg);
BString user_id;
Role* role = _GetRole(msg);
if (chat == NULL || msg->FindString("user_id", &user_id) != B_OK
|| role == NULL)
break;
chat->SetRole(user_id, role);
break;
}
case IM_ROOM_NAME_SET: case IM_ROOM_NAME_SET:
{ {
BString name; BString name;
Conversation* chat = _EnsureConversation(msg); Conversation* chat = _EnsureConversation(msg);
if (msg->FindString("chat_name", &name) != B_OK || chat == NULL) if (msg->FindString("chat_name", &name) != B_OK || chat == NULL)
break; break;
chat->SetNotifyName(name.String()); chat->SetNotifyName(name.String());
break; break;
} }
@ -464,7 +440,6 @@ Server::ImMessage(BMessage* msg)
Conversation* chat = _EnsureConversation(msg); Conversation* chat = _EnsureConversation(msg);
if (msg->FindString("subject", &subject) != B_OK || chat == NULL) if (msg->FindString("subject", &subject) != B_OK || chat == NULL)
break; break;
chat->SetNotifySubject(subject.String()); chat->SetNotifySubject(subject.String());
break; break;
} }
@ -476,13 +451,6 @@ Server::ImMessage(BMessage* msg)
conversation->GetProtocolLooper()->PostMessage(msg); conversation->GetProtocolLooper()->PostMessage(msg);
break; break;
} }
case IM_MESSAGE_SENT:
case IM_MESSAGE_RECEIVED:
{
Conversation* item = _EnsureConversation(msg);
item->ImMessage(msg);
break;
}
case IM_ROOM_INVITE_RECEIVED: case IM_ROOM_INVITE_RECEIVED:
{ {
BString chat_id; BString chat_id;
@ -987,25 +955,6 @@ Server::_EnsureConversation(BMessage* message)
} }
Role*
Server::_GetRole(BMessage* msg)
{
if (!msg)
return NULL;
BString title;
int32 perms;
int32 priority;
if (msg->FindString("role_title", &title) != B_OK
|| msg->FindInt32("role_perms", &perms) != B_OK
|| msg->FindInt32("role_priority", &priority) != B_OK)
return NULL;
return new Role(title, perms, priority);
}
void void
Server::_ProtocolNotification(ProtocolLooper* looper, BString title, Server::_ProtocolNotification(ProtocolLooper* looper, BString title,
BString desc, notification_type type) BString desc, notification_type type)

View File

@ -77,8 +77,6 @@ private:
Contact* _GetOwnContact(BMessage* message); Contact* _GetOwnContact(BMessage* message);
Conversation* _EnsureConversation(BMessage* message); Conversation* _EnsureConversation(BMessage* message);
Role* _GetRole(BMessage* msg);
void _ProtocolNotification(ProtocolLooper* looper, void _ProtocolNotification(ProtocolLooper* looper,
BString title, BString desc, BString title, BString desc,
notification_type type=B_INFORMATION_NOTIFICATION); notification_type type=B_INFORMATION_NOTIFICATION);

View File

@ -18,6 +18,7 @@
#include <StringView.h> #include <StringView.h>
#include <libinterface/BitmapView.h> #include <libinterface/BitmapView.h>
#include <libinterface/EnterTextView.h>
#include "AppMessages.h" #include "AppMessages.h"
#include "AppPreferences.h" #include "AppPreferences.h"
@ -185,6 +186,33 @@ ConversationView::ImMessage(BMessage* msg)
msg); msg);
break; break;
} }
case IM_ROOM_ROLECHANGED:
{
BString user_id = msg->FindString("user_id");
if (user_id == fConversation->GetOwnContact()->GetId()) {
Role* role = fConversation->GetRole(user_id);
if (role == NULL)
break;
int32 perms = role->fPerms;
fNameTextView->MakeEditable(perms & PERM_ROOM_NAME);
fSubjectTextView->MakeEditable(perms & PERM_ROOM_SUBJECT);
}
break;
}
case IM_SET_ROOM_NAME:
case IM_SET_ROOM_SUBJECT:
{
if (fConversation == NULL)
return;
fConversation->GetProtocolLooper()->MessageReceived(msg);
// Reset to current values; if the change went through, it'll
// come back.
fNameTextView->SetText(fConversation->GetName());
fSubjectTextView->SetText(fConversation->GetSubject());
break;
}
case IM_PROTOCOL_READY: case IM_PROTOCOL_READY:
{ {
fReceiveView->SetText(""); fReceiveView->SetText("");
@ -209,8 +237,21 @@ ConversationView::SetConversation(Conversation* chat)
if (chat == NULL) if (chat == NULL)
return; return;
fConversation = chat; fConversation = chat;
BMessage name(IM_MESSAGE);
name.AddInt32("im_what", IM_SET_ROOM_NAME);
name.AddString("chat_id", chat->GetId());
fNameTextView->SetText(chat->GetName()); fNameTextView->SetText(chat->GetName());
fNameTextView->SetMessage(name, "chat_name");
fNameTextView->SetTarget(this);
BMessage subject(IM_MESSAGE);
subject.AddInt32("im_what", IM_SET_ROOM_SUBJECT);
subject.AddString("chat_id", chat->GetId());
fSubjectTextView->SetText(chat->GetSubject()); fSubjectTextView->SetText(chat->GetSubject());
fSubjectTextView->SetMessage(subject, "subject");
fSubjectTextView->SetTarget(this);
fProtocolView->SetBitmap(chat->ProtocolBitmap()); fProtocolView->SetBitmap(chat->ProtocolBitmap());
} }
@ -273,13 +314,13 @@ ConversationView::_InitInterface()
fSendView = new SendTextView("sendView", this); fSendView = new SendTextView("sendView", this);
fNameTextView = new BTextView("roomName", be_bold_font, NULL, B_WILL_DRAW); fNameTextView = new EnterTextView("roomName", be_bold_font, NULL, B_WILL_DRAW);
fNameTextView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); fNameTextView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
fNameTextView->SetStylable(true); fNameTextView->SetStylable(true);
fNameTextView->MakeEditable(false); fNameTextView->MakeEditable(false);
fNameTextView->MakeResizable(true); fNameTextView->MakeResizable(true);
fSubjectTextView = new BTextView("roomSubject"); fSubjectTextView = new EnterTextView("roomSubject");
fSubjectTextView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); fSubjectTextView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
fSubjectTextView->MakeEditable(false); fSubjectTextView->MakeEditable(false);
fSubjectTextView->MakeResizable(true); fSubjectTextView->MakeResizable(true);

View File

@ -13,9 +13,9 @@
#include "Observer.h" #include "Observer.h"
class BStringView; class BStringView;
class BTextView;
class BitmapView; class BitmapView;
class EnterTextView;
class RenderView; class RenderView;
class SendTextView; class SendTextView;
class User; class User;
@ -61,8 +61,8 @@ private:
Conversation* fConversation; Conversation* fConversation;
BObjectList<BMessage> fMessageQueue; BObjectList<BMessage> fMessageQueue;
BTextView* fNameTextView; EnterTextView* fNameTextView;
BTextView* fSubjectTextView; EnterTextView* fSubjectTextView;
BitmapView* fProtocolView; BitmapView* fProtocolView;
BitmapView* fIcon; BitmapView* fIcon;

View File

@ -13,10 +13,12 @@
SendTextView::SendTextView(const char* name, ConversationView* convView) SendTextView::SendTextView(const char* name, ConversationView* convView)
: :
BTextView(name), EnterTextView(name),
fConversationView(convView), fConversationView(convView),
fCurrentIndex(0) fCurrentIndex(0)
{ {
SetMessage(BMessage(APP_CHAT));
SetTarget(convView);
} }
@ -35,10 +37,8 @@ SendTextView::KeyDown(const char* bytes, int32 numBytes)
if ((bytes[0] == B_ENTER) && (modifiers & B_COMMAND_KEY)) if ((bytes[0] == B_ENTER) && (modifiers & B_COMMAND_KEY))
Insert("\n"); Insert("\n");
else if (bytes[0] == B_ENTER)
fConversationView->MessageReceived(new BMessage(APP_CHAT));
else else
BTextView::KeyDown(bytes, numBytes); EnterTextView::KeyDown(bytes, numBytes);
} }

View File

@ -5,12 +5,12 @@
#ifndef _SEND_TEXT_VIEW_H #ifndef _SEND_TEXT_VIEW_H
#define _SEND_TEXT_VIEW_H #define _SEND_TEXT_VIEW_H
#include <TextView.h> #include <libinterface/EnterTextView.h>
#include "ConversationView.h" #include "ConversationView.h"
class SendTextView : public BTextView { class SendTextView : public EnterTextView {
public: public:
SendTextView(const char* name, ConversationView* convView); SendTextView(const char* name, ConversationView* convView);
@ -25,5 +25,4 @@ private:
BString fCurrentWord; BString fCurrentWord;
}; };
#endif // _SEND_TEXT_VIEW_H #endif // _SEND_TEXT_VIEW_H

View File

@ -0,0 +1,51 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "EnterTextView.h"
#include <Window.h>
EnterTextView::EnterTextView(const char* name)
:
BTextView(name),
fTarget(NULL)
{
}
EnterTextView::EnterTextView(const char* name, const BFont* initialFont,
const rgb_color* initialColor, uint32 flags)
:
BTextView(name, initialFont, initialColor, flags),
fTarget(NULL)
{
}
void
EnterTextView::KeyDown(const char* bytes, int32 numBytes)
{
int32 modifiers = Window()->CurrentMessage()->GetInt32("modifiers", 0);
if (fTarget != NULL && (bytes[0] == B_ENTER) && (modifiers == 0))
{
BMessage* msg = new BMessage(fMessage);
if (fTextSlot.IsEmpty() == false)
msg->AddString(fTextSlot.String(), Text());
fTarget->MessageReceived(msg);
}
else
BTextView::KeyDown(bytes, numBytes);
}
void
EnterTextView::SetMessage(BMessage msg, const char* textSlot)
{
fMessage = msg;
if (textSlot != NULL)
fTextSlot.SetTo(textSlot);
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef _ENTER_TEXT_VIEW_H
#define _ENTER_TEXT_VIEW_H
#include <TextView.h>
class EnterTextView : public BTextView {
public:
EnterTextView(const char* name);
EnterTextView(const char* name, const BFont* initialFont,
const rgb_color* initialColor,
uint32 flags = B_WILL_DRAW);
virtual void KeyDown(const char* bytes, int32 numBytes);
void SetTarget(BHandler* handler) { fTarget = handler; }
BMessage Message() { return fMessage; }
void SetMessage(BMessage msg, const char* textSlot = NULL);
private:
BMessage fMessage;
BHandler* fTarget;
BString fTextSlot;
};
#endif // _ENTER_TEXT_VIEW_H

View File

@ -36,6 +36,7 @@ SRCS = \
libs/libinterface/BitmapUtils.cpp \ libs/libinterface/BitmapUtils.cpp \
libs/libinterface/BitmapView.cpp \ libs/libinterface/BitmapView.cpp \
libs/libinterface/Divider.cpp \ libs/libinterface/Divider.cpp \
libs/libinterface/EnterTextView.cpp \
libs/libinterface/MenuButton.cpp \ libs/libinterface/MenuButton.cpp \
libs/libinterface/NotifyingTextView.cpp \ libs/libinterface/NotifyingTextView.cpp \
libs/libinterface/PictureView.cpp libs/libinterface/PictureView.cpp