From 131b5671c30636ec2ebcd847ca5dc09113b70b89 Mon Sep 17 00:00:00 2001 From: TheJackiMonster Date: Sat, 2 Jul 2022 18:45:40 +0200 Subject: Added list of members in a chat Signed-off-by: TheJackiMonster --- Makefile | 3 + src/application.c | 5 +- src/application.h | 4 +- src/chat.c | 68 ++++++++++++----- src/chat.h | 6 ++ src/ui/chat.h | 37 ++++++++++ src/ui/chats.c | 19 +++-- src/ui/members.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ui/members.h | 78 ++++++++++++++++++++ src/ui/messages.c | 19 ++--- src/ui/messages.h | 2 - 11 files changed, 409 insertions(+), 49 deletions(-) create mode 100644 src/ui/chat.h create mode 100644 src/ui/members.c create mode 100644 src/ui/members.h diff --git a/Makefile b/Makefile index c836442..d3ebae0 100644 --- a/Makefile +++ b/Makefile @@ -10,13 +10,16 @@ SOURCES = messenger_cli.c\ ui/accounts.c\ ui/chat_open_dialog.c\ ui/chats.c\ + ui/members.c\ ui/messages.c HEADERS = application.h\ chat.h\ ui/account_create_dialog.h\ ui/accounts.h\ + ui/chat.h\ ui/chat_open_dialog.h\ ui/chats.h\ + ui/members.h\ ui/messages.h LIBRARIES = gnunetchat gnunetutil ncurses diff --git a/src/application.c b/src/application.c index 74641c5..f3b99c5 100644 --- a/src/application.c +++ b/src/application.c @@ -45,7 +45,7 @@ application_init(MESSENGER_Application *app, noecho(); keypad(app->window, TRUE); - timeout(100); + timeout(10); } static void @@ -79,7 +79,8 @@ application_run(MESSENGER_Application *app) app ); - messages_clear(&(app->messages)); + members_clear(&(app->current.members)); + messages_clear(&(app->current.messages)); if (app->window) delwin(app->window); diff --git a/src/application.h b/src/application.h index 63e1689..ad8a7f5 100644 --- a/src/application.h +++ b/src/application.h @@ -32,8 +32,8 @@ #include "util.h" #include "ui/accounts.h" +#include "ui/chat.h" #include "ui/chats.h" -#include "ui/messages.h" typedef struct MESSENGER_Application { @@ -47,7 +47,7 @@ typedef struct MESSENGER_Application UI_ACCOUNTS_Handle accounts; UI_CHATS_Handle chats; - UI_MESSAGES_Handle messages; + UI_CHAT_Handle current; } MESSENGER_Application; void diff --git a/src/chat.c b/src/chat.c index 8ad21e5..4bf7972 100644 --- a/src/chat.c +++ b/src/chat.c @@ -35,18 +35,25 @@ _chat_refresh(MESSENGER_Application *app) app->accounts.window = NULL; app->chats.window = NULL; - app->messages.window = NULL; + app->current.members.window = NULL; + app->current.messages.window = NULL; if (!account) app->accounts.window = stdscr; else if (app->chat.context) - app->messages.window = stdscr; + { + if (app->chat.show_members) + app->current.members.window = stdscr; + else + app->current.messages.window = stdscr; + } else app->chats.window = stdscr; accounts_print(&(app->accounts), app); chats_print(&(app->chats), app); - messages_print(&(app->messages)); + members_print(&(app->current.members)); + messages_print(&(app->current.messages)); } static int @@ -63,7 +70,12 @@ _chat_event(MESSENGER_Application *app, if (!account) accounts_event(&(app->accounts), app, key); else if (app->chat.context) - messages_event(&(app->messages), app, key); + { + if (app->chat.show_members) + members_event(&(app->current.members), app, key); + else + messages_event(&(app->current.messages), app, key); + } else chats_event(&(app->chats), app, key); @@ -82,21 +94,7 @@ _chat_message(void *cls, { MESSENGER_Application *app = cls; - UI_MESSAGES_Handle *messages = (UI_MESSAGES_Handle*) ( - GNUNET_CHAT_context_get_user_pointer(context) - ); - - if (messages) - { - if (GNUNET_CHAT_KIND_DELETION == GNUNET_CHAT_message_get_kind(message)) - messages_remove( - &(app->messages), - context, - GNUNET_CHAT_message_get_target(message) - ); - - messages_add(&(app->messages), context, message); - } + chat_process_message(&(app->chat), context, message); _chat_event(app, KEY_RESIZE); return GNUNET_YES; @@ -160,3 +158,35 @@ chat_stop(MESSENGER_Chat *chat) chat->quit = GNUNET_YES; } + +void +chat_process_message(UNUSED MESSENGER_Chat *chat, + struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Message *message) +{ + enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); + + struct GNUNET_CHAT_Contact *sender = GNUNET_CHAT_message_get_sender(message); + + UI_CHAT_Handle *current = (UI_CHAT_Handle*) ( + GNUNET_CHAT_context_get_user_pointer(context) + ); + + if (!current) + return; + + bool new_member = FALSE; + + if (GNUNET_CHAT_KIND_LEAVE) + members_remove(&(current->members), sender); + else if (GNUNET_CHAT_KIND_JOIN == kind) + new_member = members_add(&(current->members), sender); + + if (GNUNET_CHAT_KIND_DELETION == kind) + messages_remove( + &(current->messages), + GNUNET_CHAT_message_get_target(message) + ); + else if ((GNUNET_CHAT_KIND_JOIN != kind) || (new_member)) + messages_add(&(current->messages), message); +} diff --git a/src/chat.h b/src/chat.h index 8d5cd0b..8f3a309 100644 --- a/src/chat.h +++ b/src/chat.h @@ -38,6 +38,7 @@ typedef struct MESSENGER_Chat struct GNUNET_SCHEDULER_Task *idle; + bool show_members; int quit; } MESSENGER_Chat; @@ -49,4 +50,9 @@ chat_start(MESSENGER_Chat *chat, void chat_stop(MESSENGER_Chat *chat); +void +chat_process_message(MESSENGER_Chat *chat, + struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Message *message); + #endif /* CHAT_H_ */ diff --git a/src/ui/chat.h b/src/ui/chat.h new file mode 100644 index 0000000..b8febf4 --- /dev/null +++ b/src/ui/chat.h @@ -0,0 +1,37 @@ +/* + This file is part of GNUnet. + Copyright (C) 2022 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file ui/chat.h + */ + +#ifndef UI_CHAT_H_ +#define UI_CHAT_H_ + +#include "members.h" +#include "messages.h" + +typedef struct UI_CHAT_Handle +{ + UI_MEMBERS_Handle members; + UI_MESSAGES_Handle messages; +} UI_CHAT_Handle; + +#endif /* UI_CHAT_H_ */ diff --git a/src/ui/chats.c b/src/ui/chats.c index dbffc26..fc7056c 100644 --- a/src/ui/chats.c +++ b/src/ui/chats.c @@ -49,10 +49,8 @@ _chats_iterate_messages(void *cls, struct GNUNET_CHAT_Context *context, const struct GNUNET_CHAT_Message *message) { - UI_MESSAGES_Handle *messages = cls; - - messages_add(messages, context, message); - + MESSENGER_Chat *chat = cls; + chat_process_message(chat, context, message); return GNUNET_YES; } @@ -101,17 +99,18 @@ chats_event(UI_CHATS_Handle *chats, { struct GNUNET_CHAT_Context *context = GNUNET_CHAT_group_get_context(chats->selected); - messages_clear(&(app->messages)); + members_clear(&(app->current.members)); + messages_clear(&(app->current.messages)); - GNUNET_CHAT_context_iterate_messages( + GNUNET_CHAT_context_set_user_pointer( context, - &_chats_iterate_messages, - &(app->messages) + &(app->current) ); - GNUNET_CHAT_context_set_user_pointer( + GNUNET_CHAT_context_iterate_messages( context, - &(app->messages) + &_chats_iterate_messages, + &(app->chat) ); app->chat.context = context; diff --git a/src/ui/members.c b/src/ui/members.c new file mode 100644 index 0000000..c500d58 --- /dev/null +++ b/src/ui/members.c @@ -0,0 +1,217 @@ +/* + This file is part of GNUnet. + Copyright (C) 2022 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file ui/members.c + */ + +#include "members.h" + +#include "../application.h" +#include "../util.h" + +void +members_event(UI_MEMBERS_Handle *members, + struct MESSENGER_Application *app, + int key) +{ + members->line_index = 0; + members->selected = NULL; + + int count = 0; + + UI_MEMBERS_List *element = members->head; + while (element) + { + count++; + + element = element->next; + } + + switch (key) + { + case 27: + case KEY_EXIT: + case '\t': + { + app->chat.show_members = FALSE; + break; + } + case KEY_UP: + { + members->line_selected--; + break; + } + case KEY_DOWN: + { + members->line_selected++; + break; + } + case '\n': + case KEY_ENTER: + { + if (members->selected) + { + // TODO + } + + break; + } + default: + break; + } + + if (members->line_selected < 0) + members->line_selected = 0; + else if (members->line_selected >= count) + members->line_selected = count - 1; + + if (!(members->window)) + return; + + const int height = getmaxy(members->window) - getbegy(members->window); + const int y = members->line_selected - members->line_offset; + + if (y < 0) + members->line_offset += y; + else if (y + 1 >= height) + members->line_offset += y + 1 - height; + + if (members->line_offset < 0) + members->line_offset = 0; + else if (members->line_offset >= count) + members->line_offset = count - 1; +} + +static void +_members_iterate_print(UI_MEMBERS_Handle *members, + const struct GNUNET_CHAT_Contact *contact) +{ + const bool selected = (members->line_selected == members->line_index); + const int y = members->line_index - members->line_offset; + + members->line_index++; + + if (y < 0) + return; + + const int height = getmaxy(members->window) - getbegy(members->window); + + if (y >= height) + return; + + const int attrs_select = A_BOLD; + + if (selected) wattron(members->window, attrs_select); + + wmove(members->window, y, 0); + + const char *name = GNUNET_CHAT_contact_get_name(contact); + wprintw(members->window, "%s", name); + + if (selected) wattroff(members->window, attrs_select); +} + +void +members_print(UI_MEMBERS_Handle *members) +{ + if (!(members->window)) + return; + + members->line_index = 0; + werase(members->window); + + UI_MEMBERS_List *element = members->head; + while (element) + { + _members_iterate_print(members, element->contact); + + element = element->next; + } +} + +void +members_clear(UI_MEMBERS_Handle *members) +{ + UI_MEMBERS_List *element; + while (members->head) + { + element = members->head; + + GNUNET_CONTAINER_DLL_remove( + members->head, + members->tail, + element + ); + + GNUNET_free(element); + } + + members->line_selected = 0; +} + +bool +members_add(UI_MEMBERS_Handle *members, + const struct GNUNET_CHAT_Contact *contact) +{ + UI_MEMBERS_List *element = members->head; + while (element) + { + if (element->contact == contact) + break; + + element = element->next; + } + + if (element) + return FALSE; + + element = GNUNET_new(UI_MEMBERS_List); + element->contact = contact; + + GNUNET_CONTAINER_DLL_insert_tail( + members->head, + members->tail, + element + ); + + return TRUE; +} + +void +members_remove(UI_MEMBERS_Handle *members, + const struct GNUNET_CHAT_Contact *contact) +{ + UI_MEMBERS_List *element = members->head; + while (element) + { + if (element->contact == contact) + break; + + element = element->next; + } + + if (element) + GNUNET_CONTAINER_DLL_remove( + members->head, + members->tail, + element + ); +} diff --git a/src/ui/members.h b/src/ui/members.h new file mode 100644 index 0000000..4f7c50d --- /dev/null +++ b/src/ui/members.h @@ -0,0 +1,78 @@ +/* + This file is part of GNUnet. + Copyright (C) 2022 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file ui/members.h + */ + +#ifndef UI_MEMBERS_H_ +#define UI_MEMBERS_H_ + +#include +#include + +#include +#include +#include + +struct MESSENGER_Application; + +typedef struct UI_MEMBERS_List +{ + const struct GNUNET_CHAT_Contact *contact; + + struct UI_MEMBERS_List *prev; + struct UI_MEMBERS_List *next; +} UI_MEMBERS_List; + +typedef struct UI_MEMBERS_Handle +{ + WINDOW *window; + + UI_MEMBERS_List *head; + UI_MEMBERS_List *tail; + + int line_index; + int line_offset; + int line_selected; + + const struct GNUNET_CHAT_Contact *selected; +} UI_MEMBERS_Handle; + +void +members_event(UI_MEMBERS_Handle *members, + struct MESSENGER_Application *app, + int key); + +void +members_print(UI_MEMBERS_Handle *members); + +void +members_clear(UI_MEMBERS_Handle *members); + +bool +members_add(UI_MEMBERS_Handle *members, + const struct GNUNET_CHAT_Contact *contact); + +void +members_remove(UI_MEMBERS_Handle *members, + const struct GNUNET_CHAT_Contact *contact); + +#endif /* UI_MEMBERS_H_ */ diff --git a/src/ui/messages.c b/src/ui/messages.c index 70d64df..9b0a692 100644 --- a/src/ui/messages.c +++ b/src/ui/messages.c @@ -86,6 +86,11 @@ messages_event(UI_MESSAGES_Handle *messages, messages->line_selected++; break; } + case '\t': + { + app->chat.show_members = TRUE; + break; + } case '\n': case KEY_ENTER: { @@ -337,7 +342,6 @@ _message_compare_timestamps(UNUSED void *cls, void messages_add(UI_MESSAGES_Handle *messages, - struct GNUNET_CHAT_Context *context, const struct GNUNET_CHAT_Message *message) { enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); @@ -351,15 +355,6 @@ messages_add(UI_MESSAGES_Handle *messages, break; } - struct GNUNET_CHAT_Contact *sender = GNUNET_CHAT_message_get_sender(message); - struct GNUNET_CHAT_Group *group = GNUNET_CHAT_context_get_group(context); - - if ((GNUNET_CHAT_KIND_JOIN == kind) && - (GNUNET_CHAT_member_get_user_pointer(group, sender))) - { - return; - } - const int height = getmaxy(messages->window) - getbegy(messages->window); const int line_height = height - 2; @@ -384,9 +379,6 @@ messages_add(UI_MESSAGES_Handle *messages, element ); - if (GNUNET_CHAT_KIND_JOIN == kind) - GNUNET_CHAT_member_set_user_pointer(group, sender, element); - if (messages->line_selected >= count) messages->line_selected = count + 1; @@ -396,7 +388,6 @@ messages_add(UI_MESSAGES_Handle *messages, void messages_remove(UI_MESSAGES_Handle *messages, - UNUSED struct GNUNET_CHAT_Context *context, const struct GNUNET_CHAT_Message *message) { UI_MESSAGES_List *element = messages->head; diff --git a/src/ui/messages.h b/src/ui/messages.h index d969782..06de97f 100644 --- a/src/ui/messages.h +++ b/src/ui/messages.h @@ -75,12 +75,10 @@ messages_clear(UI_MESSAGES_Handle *messages); void messages_add(UI_MESSAGES_Handle *messages, - struct GNUNET_CHAT_Context *context, const struct GNUNET_CHAT_Message *message); void messages_remove(UI_MESSAGES_Handle *messages, - struct GNUNET_CHAT_Context *context, const struct GNUNET_CHAT_Message *message); #endif /* UI_MESSAGES_H_ */ -- cgit v1.2.3