diff options
author | TheJackiMonster <thejackimonster@gmail.com> | 2022-04-24 21:18:48 +0200 |
---|---|---|
committer | TheJackiMonster <thejackimonster@gmail.com> | 2022-04-24 21:18:48 +0200 |
commit | 31f06baed66c24e82e3cf50326ef66ec2b8ab8c6 (patch) | |
tree | 6611780e6946b63963ddfd4c1a1e5224addbb113 | |
parent | d75a06e86407204e302fe3a49d8e2c137d1fbe2b (diff) |
Added list of chats and implemented switching back and forth
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/application.c | 2 | ||||
-rw-r--r-- | src/application.h | 2 | ||||
-rw-r--r-- | src/chat.c | 45 | ||||
-rw-r--r-- | src/chat.h | 2 | ||||
-rw-r--r-- | src/ui/accounts.c | 15 | ||||
-rw-r--r-- | src/ui/accounts.h | 9 | ||||
-rw-r--r-- | src/ui/chats.c | 189 | ||||
-rw-r--r-- | src/ui/chats.h | 57 | ||||
-rw-r--r-- | src/ui/messages.c | 209 | ||||
-rw-r--r-- | src/ui/messages.h | 20 | ||||
-rw-r--r-- | src/util.h | 2 |
12 files changed, 512 insertions, 42 deletions
@@ -7,10 +7,12 @@ SOURCES = messenger_cli.c\ application.c\ chat.c\ ui/accounts.c\ + ui/chats.c\ ui/messages.c HEADERS = application.h\ chat.h\ ui/accounts.h\ + ui/chats.h\ ui/messages.h LIBRARIES = gnunetchat gnunetutil ncurses diff --git a/src/application.c b/src/application.c index 78d5a77..a56fd43 100644 --- a/src/application.c +++ b/src/application.c @@ -69,6 +69,8 @@ application_run(MESSENGER_Application *app) app ); + messages_clear(&(app->messages)); + endwin(); } diff --git a/src/application.h b/src/application.h index 0eeb37e..3e4bede 100644 --- a/src/application.h +++ b/src/application.h @@ -32,6 +32,7 @@ #include "util.h" #include "ui/accounts.h" +#include "ui/chats.h" #include "ui/messages.h" typedef struct MESSENGER_Application @@ -44,6 +45,7 @@ typedef struct MESSENGER_Application MESSENGER_Chat chat; UI_ACCOUNTS_Handle accounts; + UI_CHATS_Handle chats; UI_MESSAGES_Handle messages; } MESSENGER_Application; @@ -34,15 +34,19 @@ _chat_refresh(MESSENGER_Application *app) ); app->accounts.window = NULL; + app->chats.window = NULL; app->messages.window = NULL; if (!account) app->accounts.window = stdscr; else if (app->chat.context) app->messages.window = stdscr; + else + app->chats.window = stdscr; accounts_print(&(app->accounts), app); - messages_print(&(app->messages), app); + chats_print(&(app->chats), app); + messages_print(&(app->messages)); } static int @@ -56,36 +60,43 @@ _chat_event(MESSENGER_Application *app, app->chat.handle ); - if ('q' == key) - return 1; - if (!account) accounts_event(&(app->accounts), app, key); else if (app->chat.context) messages_event(&(app->messages), app, key); else - { - struct GNUNET_CHAT_Group *test = GNUNET_CHAT_group_create( - app->chat.handle, - "test" - ); + chats_event(&(app->chats), app, key); - app->chat.context = GNUNET_CHAT_group_get_context(test); - } + if (GNUNET_YES == app->chat.quit) + return 1; refresh: _chat_refresh(app); return 0; } -int lc = 0; - static int _chat_message(void *cls, - UNUSED struct GNUNET_CHAT_Context *context, - UNUSED const struct GNUNET_CHAT_Message *message) + struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Message *message) { 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), + GNUNET_CHAT_message_get_target(message) + ); + + messages_add(&(app->messages), message); + } + _chat_event(app, KEY_RESIZE); return GNUNET_YES; } @@ -130,6 +141,8 @@ chat_start(MESSENGER_Chat *chat, &_chat_idle, app ); + + chat->quit = GNUNET_NO; } void @@ -143,4 +156,6 @@ chat_stop(MESSENGER_Chat *chat) GNUNET_CHAT_stop(chat->handle); chat->handle = NULL; + + chat->quit = GNUNET_YES; } @@ -37,6 +37,8 @@ typedef struct MESSENGER_Chat struct GNUNET_CHAT_Context *context; struct GNUNET_SCHEDULER_Task *idle; + + int quit; } MESSENGER_Chat; void diff --git a/src/ui/accounts.c b/src/ui/accounts.c index ef44d13..e933d5d 100644 --- a/src/ui/accounts.c +++ b/src/ui/accounts.c @@ -23,9 +23,9 @@ */ #include "accounts.h" -#include "../application.h" -#include <stdbool.h> +#include "../application.h" +#include "../util.h" int _accounts_iterate(void *cls, @@ -46,7 +46,7 @@ _accounts_iterate(void *cls, void accounts_event(UI_ACCOUNTS_Handle *accounts, - struct MESSENGER_Application *app, + MESSENGER_Application *app, int key) { accounts->line_index = 0; @@ -60,6 +60,12 @@ accounts_event(UI_ACCOUNTS_Handle *accounts, switch (key) { + case 27: + case KEY_EXIT: + { + app->chat.quit = GNUNET_YES; + break; + } case KEY_UP: { accounts->line_selected--; @@ -140,12 +146,13 @@ _accounts_iterate_print(void *cls, void accounts_print(UI_ACCOUNTS_Handle *accounts, - struct MESSENGER_Application *app) + MESSENGER_Application *app) { if (!(accounts->window)) return; accounts->line_index = 0; + werase(accounts->window); GNUNET_CHAT_iterate_accounts( app->chat.handle, diff --git a/src/ui/accounts.h b/src/ui/accounts.h index 63b0af2..285f97e 100644 --- a/src/ui/accounts.h +++ b/src/ui/accounts.h @@ -28,8 +28,11 @@ #include <stdlib.h> #include <curses.h> +#include <gnunet/platform.h> +#include <gnunet/gnunet_chat_lib.h> +#include <gnunet/gnunet_util_lib.h> + struct MESSENGER_Application; -struct GNUNET_CHAT_Account; typedef struct UI_ACCOUNTS_Handle { @@ -44,11 +47,11 @@ typedef struct UI_ACCOUNTS_Handle void accounts_event(UI_ACCOUNTS_Handle *accounts, - struct MESSENGER_Application *app, + struct MESSENGER_Application *app, int key); void accounts_print(UI_ACCOUNTS_Handle *accounts, - struct MESSENGER_Application *app); + struct MESSENGER_Application *app); #endif /* UI_ACCOUNTS_H_ */ diff --git a/src/ui/chats.c b/src/ui/chats.c new file mode 100644 index 0000000..991e43b --- /dev/null +++ b/src/ui/chats.c @@ -0,0 +1,189 @@ +/* + 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 <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file ui/chats.c + */ + +#include "chats.h" + +#include "../application.h" +#include "../util.h" + +static int +_chats_iterate(void *cls, + UNUSED struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Group *group) +{ + UI_CHATS_Handle *chats = cls; + + const bool selected = (chats->line_selected == chats->line_index); + + chats->line_index++; + + if (selected) + chats->selected = GNUNET_CHAT_group_get_context(group); + + return GNUNET_YES; +} + +static int +_chats_iterate_messages(void *cls, + UNUSED struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Message *message) +{ + UI_MESSAGES_Handle *messages = cls; + + messages_add(messages, message); + + return GNUNET_YES; +} + +void +chats_event(UI_CHATS_Handle *chats, + MESSENGER_Application *app, + int key) +{ + chats->line_index = 0; + chats->selected = NULL; + + int count = GNUNET_CHAT_iterate_groups( + app->chat.handle, + &_chats_iterate, + chats + ); + + switch (key) + { + case 27: + case KEY_EXIT: + { + GNUNET_CHAT_disconnect(app->chat.handle); + break; + } + case KEY_UP: + { + chats->line_selected--; + break; + } + case KEY_DOWN: + { + chats->line_selected++; + break; + } + case '\n': + case KEY_ENTER: + { + if (chats->selected) + { + messages_clear(&(app->messages)); + + GNUNET_CHAT_context_iterate_messages( + chats->selected, + &_chats_iterate_messages, + &(app->messages) + ); + + GNUNET_CHAT_context_set_user_pointer( + chats->selected, + &(app->messages) + ); + + app->chat.context = chats->selected; + } + + break; + } + default: + break; + } + + if (chats->line_selected < 0) + chats->line_selected = 0; + else if (chats->line_selected >= count) + chats->line_selected = count - 1; + + if (!(chats->window)) + return; + + const int height = getmaxy(chats->window) - getbegy(chats->window); + const int y = chats->line_selected - chats->line_offset; + + if (y < 0) + chats->line_offset += y; + else if (y + 1 >= height) + chats->line_offset += y + 1 - height; + + if (chats->line_offset < 0) + chats->line_offset = 0; + else if (chats->line_offset >= count) + chats->line_offset = count - 1; +} + +int +_chats_iterate_print(void *cls, + UNUSED struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Group *group) +{ + UI_CHATS_Handle *chats = cls; + + const bool selected = (chats->line_selected == chats->line_index); + const int y = chats->line_index - chats->line_offset; + + chats->line_index++; + + if (y < 0) + return GNUNET_YES; + + const int height = getmaxy(chats->window) - getbegy(chats->window); + + if (y >= height) + return GNUNET_NO; + + const char *name = GNUNET_CHAT_group_get_name(group); + + const int attrs_select = A_BOLD; + + if (selected) wattron(chats->window, attrs_select); + + wmove(chats->window, y, 0); + wprintw(chats->window, "%s", name); + + if (selected) wattroff(chats->window, attrs_select); + + return GNUNET_YES; +} + +void +chats_print(UI_CHATS_Handle *chats, + MESSENGER_Application *app) +{ + if (!(chats->window)) + return; + + chats->line_index = 0; + werase(chats->window); + + GNUNET_CHAT_iterate_groups( + app->chat.handle, + &_chats_iterate_print, + chats + ); +} diff --git a/src/ui/chats.h b/src/ui/chats.h new file mode 100644 index 0000000..9ffee88 --- /dev/null +++ b/src/ui/chats.h @@ -0,0 +1,57 @@ +/* + 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 <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file ui/chats.h + */ + +#ifndef UI_CHATS_H_ +#define UI_CHATS_H_ + +#include <stdlib.h> +#include <curses.h> + +#include <gnunet/platform.h> +#include <gnunet/gnunet_chat_lib.h> +#include <gnunet/gnunet_util_lib.h> + +struct MESSENGER_Application; + +typedef struct UI_CHATS_Handle +{ + WINDOW *window; + + int line_index; + int line_offset; + int line_selected; + + struct GNUNET_CHAT_Context *selected; +} UI_CHATS_Handle; + +void +chats_event(UI_CHATS_Handle *chats, + struct MESSENGER_Application *app, + int key); + +void +chats_print(UI_CHATS_Handle *chats, + struct MESSENGER_Application *app); + +#endif /* UI_CHATS_H_ */ diff --git a/src/ui/messages.c b/src/ui/messages.c index 780dd45..79a7cab 100644 --- a/src/ui/messages.c +++ b/src/ui/messages.c @@ -25,56 +25,231 @@ #include "messages.h" #include "../application.h" +#include "../util.h" + +void +_messages_iterate(UI_MESSAGES_Handle *messages, + const struct GNUNET_CHAT_Message *message) +{ + const bool selected = (messages->line_selected == messages->line_index); + + messages->line_index++; + + if (selected) + messages->selected = message; +} void messages_event(UI_MESSAGES_Handle *messages, - struct MESSENGER_Application *app, + MESSENGER_Application *app, int key) { - // TODO + messages->line_index = 0; + messages->selected = NULL; + + int count = 0; + + UI_MESSAGES_List *element = messages->head; + while (element) + { + _messages_iterate(messages, element->message); + count++; + + element = element->next; + } + + switch (key) + { + case 27: + case KEY_EXIT: + { + app->chat.context = NULL; + break; + } + case KEY_UP: + { + messages->line_selected--; + break; + } + case KEY_DOWN: + { + messages->line_selected++; + break; + } + case '\n': + case KEY_ENTER: + { + if (messages->selected) + GNUNET_CHAT_message_delete( + messages->selected, + GNUNET_TIME_relative_get_zero_() + ); + + break; + } + default: + break; + } + + if (messages->line_selected < 0) + messages->line_selected = 0; + else if (messages->line_selected >= count) + messages->line_selected = count - 1; + + if (!(messages->window)) + return; + + const int height = getmaxy(messages->window) - getbegy(messages->window); + const int y = messages->line_selected - messages->line_offset; + + if (y < 0) + messages->line_offset += y; + else if (y + 1 >= height) + messages->line_offset += y + 1 - height; + + if (messages->line_offset < 0) + messages->line_offset = 0; + else if (messages->line_offset >= count) + messages->line_offset = count - 1; } -int -_messages_iterate_print(void *cls, - struct GNUNET_CHAT_Context *context, +void +_messages_iterate_print(UI_MESSAGES_Handle *messages, const struct GNUNET_CHAT_Message *message) { - UI_MESSAGES_Handle *messages = cls; + const bool selected = (messages->line_selected == messages->line_index); + const int y = messages->line_index - messages->line_offset; + + messages->line_index++; + + if (y < 0) + return; - const int y = messages->line_index++; + const int height = getmaxy(messages->window) - getbegy(messages->window); + + if (y >= height) + return; enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); + struct GNUNET_CHAT_Contact *sender = GNUNET_CHAT_message_get_sender(message); + + const char *name = sender? GNUNET_CHAT_contact_get_name(sender) : NULL; const char *text = GNUNET_CHAT_message_get_text(message); struct GNUNET_TIME_Absolute timestamp = GNUNET_CHAT_message_get_timestamp( message ); + const int attrs_select = A_BOLD; + + if (selected) wattron(messages->window, attrs_select); + wmove(messages->window, y, 0); wprintw( messages->window, - "%s | [%d]: %s", + "%s | [%d] %s: %s", GNUNET_TIME_absolute2s(timestamp), (int) kind, + name, text ); - return GNUNET_YES; + if (selected) wattroff(messages->window, attrs_select); } void -messages_print(UI_MESSAGES_Handle *messages, - struct MESSENGER_Application *app) +messages_print(UI_MESSAGES_Handle *messages) { if (!(messages->window)) return; - struct GNUNET_CHAT_Context *context = app->chat.context; - messages->line_index = 0; - GNUNET_CHAT_context_iterate_messages( - context, - _messages_iterate_print, - messages + werase(messages->window); + + UI_MESSAGES_List *element = messages->head; + while (element) + { + _messages_iterate_print(messages, element->message); + element = element->next; + } +} + +void +messages_clear(UI_MESSAGES_Handle *messages) +{ + UI_MESSAGES_List *element; + while (messages->head) + { + element = messages->head; + + GNUNET_CONTAINER_DLL_remove( + messages->head, + messages->tail, + element + ); + + GNUNET_free(element); + } +} + +static int +_message_compare_timestamps(UNUSED void *cls, + UI_MESSAGES_List *list0, + UI_MESSAGES_List *list1) +{ + struct GNUNET_TIME_Absolute time0, time1; + + if ((!list0) || (!list1)) + return 0; + + time0 = GNUNET_CHAT_message_get_timestamp(list0->message); + time1 = GNUNET_CHAT_message_get_timestamp(list1->message); + + if (GNUNET_TIME_absolute_cmp(time0, >, time1)) + return -1; + else if (GNUNET_TIME_absolute_cmp(time0, <, time1)) + return +1; + else + return 0; +} + +void +messages_add(UI_MESSAGES_Handle *messages, + const struct GNUNET_CHAT_Message *message) +{ + if (GNUNET_CHAT_KIND_DELETION == GNUNET_CHAT_message_get_kind(message)) + return; + + UI_MESSAGES_List *element = GNUNET_new(UI_MESSAGES_List); + element->message = message; + + GNUNET_CONTAINER_DLL_insert_sorted( + UI_MESSAGES_List, + _message_compare_timestamps, + NULL, + messages->head, + messages->tail, + element ); } + +void +messages_remove(UI_MESSAGES_Handle *messages, + const struct GNUNET_CHAT_Message *message) +{ + UI_MESSAGES_List *element = messages->head; + while (element) + { + if (element->message == message) + break; + + element = element->next; + } + + if (element) + GNUNET_CONTAINER_DLL_remove( + messages->head, + messages->tail, + element + ); +} diff --git a/src/ui/messages.h b/src/ui/messages.h index 305ad01..b42bb1b 100644 --- a/src/ui/messages.h +++ b/src/ui/messages.h @@ -50,15 +50,29 @@ typedef struct UI_MESSAGES_Handle UI_MESSAGES_List *tail; int line_index; + int line_offset; + int line_selected; + + const struct GNUNET_CHAT_Message *selected; } UI_MESSAGES_Handle; void messages_event(UI_MESSAGES_Handle *messages, - struct MESSENGER_Application *app, + struct MESSENGER_Application *app, int key); void -messages_print(UI_MESSAGES_Handle *messages, - struct MESSENGER_Application *app); +messages_print(UI_MESSAGES_Handle *messages); + +void +messages_clear(UI_MESSAGES_Handle *messages); + +void +messages_add(UI_MESSAGES_Handle *messages, + const struct GNUNET_CHAT_Message *message); + +void +messages_remove(UI_MESSAGES_Handle *messages, + const struct GNUNET_CHAT_Message *message); #endif /* UI_MESSAGES_H_ */ @@ -25,6 +25,8 @@ #ifndef UTIL_H_ #define UTIL_H_ +#include <stdbool.h> + #define UNUSED __attribute__((unused)) #endif /* UTIL_H_ */ |