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) | |
download | messenger-cli-31f06baed66c24e82e3cf50326ef66ec2b8ab8c6.tar.gz messenger-cli-31f06baed66c24e82e3cf50326ef66ec2b8ab8c6.zip |
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\ | |||
7 | application.c\ | 7 | application.c\ |
8 | chat.c\ | 8 | chat.c\ |
9 | ui/accounts.c\ | 9 | ui/accounts.c\ |
10 | ui/chats.c\ | ||
10 | ui/messages.c | 11 | ui/messages.c |
11 | HEADERS = application.h\ | 12 | HEADERS = application.h\ |
12 | chat.h\ | 13 | chat.h\ |
13 | ui/accounts.h\ | 14 | ui/accounts.h\ |
15 | ui/chats.h\ | ||
14 | ui/messages.h | 16 | ui/messages.h |
15 | 17 | ||
16 | LIBRARIES = gnunetchat gnunetutil ncurses | 18 | 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) | |||
69 | app | 69 | app |
70 | ); | 70 | ); |
71 | 71 | ||
72 | messages_clear(&(app->messages)); | ||
73 | |||
72 | endwin(); | 74 | endwin(); |
73 | } | 75 | } |
74 | 76 | ||
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 @@ | |||
32 | #include "util.h" | 32 | #include "util.h" |
33 | 33 | ||
34 | #include "ui/accounts.h" | 34 | #include "ui/accounts.h" |
35 | #include "ui/chats.h" | ||
35 | #include "ui/messages.h" | 36 | #include "ui/messages.h" |
36 | 37 | ||
37 | typedef struct MESSENGER_Application | 38 | typedef struct MESSENGER_Application |
@@ -44,6 +45,7 @@ typedef struct MESSENGER_Application | |||
44 | MESSENGER_Chat chat; | 45 | MESSENGER_Chat chat; |
45 | 46 | ||
46 | UI_ACCOUNTS_Handle accounts; | 47 | UI_ACCOUNTS_Handle accounts; |
48 | UI_CHATS_Handle chats; | ||
47 | UI_MESSAGES_Handle messages; | 49 | UI_MESSAGES_Handle messages; |
48 | } MESSENGER_Application; | 50 | } MESSENGER_Application; |
49 | 51 | ||
@@ -34,15 +34,19 @@ _chat_refresh(MESSENGER_Application *app) | |||
34 | ); | 34 | ); |
35 | 35 | ||
36 | app->accounts.window = NULL; | 36 | app->accounts.window = NULL; |
37 | app->chats.window = NULL; | ||
37 | app->messages.window = NULL; | 38 | app->messages.window = NULL; |
38 | 39 | ||
39 | if (!account) | 40 | if (!account) |
40 | app->accounts.window = stdscr; | 41 | app->accounts.window = stdscr; |
41 | else if (app->chat.context) | 42 | else if (app->chat.context) |
42 | app->messages.window = stdscr; | 43 | app->messages.window = stdscr; |
44 | else | ||
45 | app->chats.window = stdscr; | ||
43 | 46 | ||
44 | accounts_print(&(app->accounts), app); | 47 | accounts_print(&(app->accounts), app); |
45 | messages_print(&(app->messages), app); | 48 | chats_print(&(app->chats), app); |
49 | messages_print(&(app->messages)); | ||
46 | } | 50 | } |
47 | 51 | ||
48 | static int | 52 | static int |
@@ -56,36 +60,43 @@ _chat_event(MESSENGER_Application *app, | |||
56 | app->chat.handle | 60 | app->chat.handle |
57 | ); | 61 | ); |
58 | 62 | ||
59 | if ('q' == key) | ||
60 | return 1; | ||
61 | |||
62 | if (!account) | 63 | if (!account) |
63 | accounts_event(&(app->accounts), app, key); | 64 | accounts_event(&(app->accounts), app, key); |
64 | else if (app->chat.context) | 65 | else if (app->chat.context) |
65 | messages_event(&(app->messages), app, key); | 66 | messages_event(&(app->messages), app, key); |
66 | else | 67 | else |
67 | { | 68 | chats_event(&(app->chats), app, key); |
68 | struct GNUNET_CHAT_Group *test = GNUNET_CHAT_group_create( | ||
69 | app->chat.handle, | ||
70 | "test" | ||
71 | ); | ||
72 | 69 | ||
73 | app->chat.context = GNUNET_CHAT_group_get_context(test); | 70 | if (GNUNET_YES == app->chat.quit) |
74 | } | 71 | return 1; |
75 | 72 | ||
76 | refresh: | 73 | refresh: |
77 | _chat_refresh(app); | 74 | _chat_refresh(app); |
78 | return 0; | 75 | return 0; |
79 | } | 76 | } |
80 | 77 | ||
81 | int lc = 0; | ||
82 | |||
83 | static int | 78 | static int |
84 | _chat_message(void *cls, | 79 | _chat_message(void *cls, |
85 | UNUSED struct GNUNET_CHAT_Context *context, | 80 | struct GNUNET_CHAT_Context *context, |
86 | UNUSED const struct GNUNET_CHAT_Message *message) | 81 | const struct GNUNET_CHAT_Message *message) |
87 | { | 82 | { |
88 | MESSENGER_Application *app = cls; | 83 | MESSENGER_Application *app = cls; |
84 | |||
85 | UI_MESSAGES_Handle *messages = (UI_MESSAGES_Handle*) ( | ||
86 | GNUNET_CHAT_context_get_user_pointer(context) | ||
87 | ); | ||
88 | |||
89 | if (messages) | ||
90 | { | ||
91 | if (GNUNET_CHAT_KIND_DELETION == GNUNET_CHAT_message_get_kind(message)) | ||
92 | messages_remove( | ||
93 | &(app->messages), | ||
94 | GNUNET_CHAT_message_get_target(message) | ||
95 | ); | ||
96 | |||
97 | messages_add(&(app->messages), message); | ||
98 | } | ||
99 | |||
89 | _chat_event(app, KEY_RESIZE); | 100 | _chat_event(app, KEY_RESIZE); |
90 | return GNUNET_YES; | 101 | return GNUNET_YES; |
91 | } | 102 | } |
@@ -130,6 +141,8 @@ chat_start(MESSENGER_Chat *chat, | |||
130 | &_chat_idle, | 141 | &_chat_idle, |
131 | app | 142 | app |
132 | ); | 143 | ); |
144 | |||
145 | chat->quit = GNUNET_NO; | ||
133 | } | 146 | } |
134 | 147 | ||
135 | void | 148 | void |
@@ -143,4 +156,6 @@ chat_stop(MESSENGER_Chat *chat) | |||
143 | 156 | ||
144 | GNUNET_CHAT_stop(chat->handle); | 157 | GNUNET_CHAT_stop(chat->handle); |
145 | chat->handle = NULL; | 158 | chat->handle = NULL; |
159 | |||
160 | chat->quit = GNUNET_YES; | ||
146 | } | 161 | } |
@@ -37,6 +37,8 @@ typedef struct MESSENGER_Chat | |||
37 | struct GNUNET_CHAT_Context *context; | 37 | struct GNUNET_CHAT_Context *context; |
38 | 38 | ||
39 | struct GNUNET_SCHEDULER_Task *idle; | 39 | struct GNUNET_SCHEDULER_Task *idle; |
40 | |||
41 | int quit; | ||
40 | } MESSENGER_Chat; | 42 | } MESSENGER_Chat; |
41 | 43 | ||
42 | void | 44 | 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 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "accounts.h" | 25 | #include "accounts.h" |
26 | #include "../application.h" | ||
27 | 26 | ||
28 | #include <stdbool.h> | 27 | #include "../application.h" |
28 | #include "../util.h" | ||
29 | 29 | ||
30 | int | 30 | int |
31 | _accounts_iterate(void *cls, | 31 | _accounts_iterate(void *cls, |
@@ -46,7 +46,7 @@ _accounts_iterate(void *cls, | |||
46 | 46 | ||
47 | void | 47 | void |
48 | accounts_event(UI_ACCOUNTS_Handle *accounts, | 48 | accounts_event(UI_ACCOUNTS_Handle *accounts, |
49 | struct MESSENGER_Application *app, | 49 | MESSENGER_Application *app, |
50 | int key) | 50 | int key) |
51 | { | 51 | { |
52 | accounts->line_index = 0; | 52 | accounts->line_index = 0; |
@@ -60,6 +60,12 @@ accounts_event(UI_ACCOUNTS_Handle *accounts, | |||
60 | 60 | ||
61 | switch (key) | 61 | switch (key) |
62 | { | 62 | { |
63 | case 27: | ||
64 | case KEY_EXIT: | ||
65 | { | ||
66 | app->chat.quit = GNUNET_YES; | ||
67 | break; | ||
68 | } | ||
63 | case KEY_UP: | 69 | case KEY_UP: |
64 | { | 70 | { |
65 | accounts->line_selected--; | 71 | accounts->line_selected--; |
@@ -140,12 +146,13 @@ _accounts_iterate_print(void *cls, | |||
140 | 146 | ||
141 | void | 147 | void |
142 | accounts_print(UI_ACCOUNTS_Handle *accounts, | 148 | accounts_print(UI_ACCOUNTS_Handle *accounts, |
143 | struct MESSENGER_Application *app) | 149 | MESSENGER_Application *app) |
144 | { | 150 | { |
145 | if (!(accounts->window)) | 151 | if (!(accounts->window)) |
146 | return; | 152 | return; |
147 | 153 | ||
148 | accounts->line_index = 0; | 154 | accounts->line_index = 0; |
155 | werase(accounts->window); | ||
149 | 156 | ||
150 | GNUNET_CHAT_iterate_accounts( | 157 | GNUNET_CHAT_iterate_accounts( |
151 | app->chat.handle, | 158 | 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 @@ | |||
28 | #include <stdlib.h> | 28 | #include <stdlib.h> |
29 | #include <curses.h> | 29 | #include <curses.h> |
30 | 30 | ||
31 | #include <gnunet/platform.h> | ||
32 | #include <gnunet/gnunet_chat_lib.h> | ||
33 | #include <gnunet/gnunet_util_lib.h> | ||
34 | |||
31 | struct MESSENGER_Application; | 35 | struct MESSENGER_Application; |
32 | struct GNUNET_CHAT_Account; | ||
33 | 36 | ||
34 | typedef struct UI_ACCOUNTS_Handle | 37 | typedef struct UI_ACCOUNTS_Handle |
35 | { | 38 | { |
@@ -44,11 +47,11 @@ typedef struct UI_ACCOUNTS_Handle | |||
44 | 47 | ||
45 | void | 48 | void |
46 | accounts_event(UI_ACCOUNTS_Handle *accounts, | 49 | accounts_event(UI_ACCOUNTS_Handle *accounts, |
47 | struct MESSENGER_Application *app, | 50 | struct MESSENGER_Application *app, |
48 | int key); | 51 | int key); |
49 | 52 | ||
50 | void | 53 | void |
51 | accounts_print(UI_ACCOUNTS_Handle *accounts, | 54 | accounts_print(UI_ACCOUNTS_Handle *accounts, |
52 | struct MESSENGER_Application *app); | 55 | struct MESSENGER_Application *app); |
53 | 56 | ||
54 | #endif /* UI_ACCOUNTS_H_ */ | 57 | #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 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/chats.c | ||
23 | */ | ||
24 | |||
25 | #include "chats.h" | ||
26 | |||
27 | #include "../application.h" | ||
28 | #include "../util.h" | ||
29 | |||
30 | static int | ||
31 | _chats_iterate(void *cls, | ||
32 | UNUSED struct GNUNET_CHAT_Handle *handle, | ||
33 | struct GNUNET_CHAT_Group *group) | ||
34 | { | ||
35 | UI_CHATS_Handle *chats = cls; | ||
36 | |||
37 | const bool selected = (chats->line_selected == chats->line_index); | ||
38 | |||
39 | chats->line_index++; | ||
40 | |||
41 | if (selected) | ||
42 | chats->selected = GNUNET_CHAT_group_get_context(group); | ||
43 | |||
44 | return GNUNET_YES; | ||
45 | } | ||
46 | |||
47 | static int | ||
48 | _chats_iterate_messages(void *cls, | ||
49 | UNUSED struct GNUNET_CHAT_Context *context, | ||
50 | const struct GNUNET_CHAT_Message *message) | ||
51 | { | ||
52 | UI_MESSAGES_Handle *messages = cls; | ||
53 | |||
54 | messages_add(messages, message); | ||
55 | |||
56 | return GNUNET_YES; | ||
57 | } | ||
58 | |||
59 | void | ||
60 | chats_event(UI_CHATS_Handle *chats, | ||
61 | MESSENGER_Application *app, | ||
62 | int key) | ||
63 | { | ||
64 | chats->line_index = 0; | ||
65 | chats->selected = NULL; | ||
66 | |||
67 | int count = GNUNET_CHAT_iterate_groups( | ||
68 | app->chat.handle, | ||
69 | &_chats_iterate, | ||
70 | chats | ||
71 | ); | ||
72 | |||
73 | switch (key) | ||
74 | { | ||
75 | case 27: | ||
76 | case KEY_EXIT: | ||
77 | { | ||
78 | GNUNET_CHAT_disconnect(app->chat.handle); | ||
79 | break; | ||
80 | } | ||
81 | case KEY_UP: | ||
82 | { | ||
83 | chats->line_selected--; | ||
84 | break; | ||
85 | } | ||
86 | case KEY_DOWN: | ||
87 | { | ||
88 | chats->line_selected++; | ||
89 | break; | ||
90 | } | ||
91 | case '\n': | ||
92 | case KEY_ENTER: | ||
93 | { | ||
94 | if (chats->selected) | ||
95 | { | ||
96 | messages_clear(&(app->messages)); | ||
97 | |||
98 | GNUNET_CHAT_context_iterate_messages( | ||
99 | chats->selected, | ||
100 | &_chats_iterate_messages, | ||
101 | &(app->messages) | ||
102 | ); | ||
103 | |||
104 | GNUNET_CHAT_context_set_user_pointer( | ||
105 | chats->selected, | ||
106 | &(app->messages) | ||
107 | ); | ||
108 | |||
109 | app->chat.context = chats->selected; | ||
110 | } | ||
111 | |||
112 | break; | ||
113 | } | ||
114 | default: | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | if (chats->line_selected < 0) | ||
119 | chats->line_selected = 0; | ||
120 | else if (chats->line_selected >= count) | ||
121 | chats->line_selected = count - 1; | ||
122 | |||
123 | if (!(chats->window)) | ||
124 | return; | ||
125 | |||
126 | const int height = getmaxy(chats->window) - getbegy(chats->window); | ||
127 | const int y = chats->line_selected - chats->line_offset; | ||
128 | |||
129 | if (y < 0) | ||
130 | chats->line_offset += y; | ||
131 | else if (y + 1 >= height) | ||
132 | chats->line_offset += y + 1 - height; | ||
133 | |||
134 | if (chats->line_offset < 0) | ||
135 | chats->line_offset = 0; | ||
136 | else if (chats->line_offset >= count) | ||
137 | chats->line_offset = count - 1; | ||
138 | } | ||
139 | |||
140 | int | ||
141 | _chats_iterate_print(void *cls, | ||
142 | UNUSED struct GNUNET_CHAT_Handle *handle, | ||
143 | struct GNUNET_CHAT_Group *group) | ||
144 | { | ||
145 | UI_CHATS_Handle *chats = cls; | ||
146 | |||
147 | const bool selected = (chats->line_selected == chats->line_index); | ||
148 | const int y = chats->line_index - chats->line_offset; | ||
149 | |||
150 | chats->line_index++; | ||
151 | |||
152 | if (y < 0) | ||
153 | return GNUNET_YES; | ||
154 | |||
155 | const int height = getmaxy(chats->window) - getbegy(chats->window); | ||
156 | |||
157 | if (y >= height) | ||
158 | return GNUNET_NO; | ||
159 | |||
160 | const char *name = GNUNET_CHAT_group_get_name(group); | ||
161 | |||
162 | const int attrs_select = A_BOLD; | ||
163 | |||
164 | if (selected) wattron(chats->window, attrs_select); | ||
165 | |||
166 | wmove(chats->window, y, 0); | ||
167 | wprintw(chats->window, "%s", name); | ||
168 | |||
169 | if (selected) wattroff(chats->window, attrs_select); | ||
170 | |||
171 | return GNUNET_YES; | ||
172 | } | ||
173 | |||
174 | void | ||
175 | chats_print(UI_CHATS_Handle *chats, | ||
176 | MESSENGER_Application *app) | ||
177 | { | ||
178 | if (!(chats->window)) | ||
179 | return; | ||
180 | |||
181 | chats->line_index = 0; | ||
182 | werase(chats->window); | ||
183 | |||
184 | GNUNET_CHAT_iterate_groups( | ||
185 | app->chat.handle, | ||
186 | &_chats_iterate_print, | ||
187 | chats | ||
188 | ); | ||
189 | } | ||
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 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/chats.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_CHATS_H_ | ||
26 | #define UI_CHATS_H_ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <curses.h> | ||
30 | |||
31 | #include <gnunet/platform.h> | ||
32 | #include <gnunet/gnunet_chat_lib.h> | ||
33 | #include <gnunet/gnunet_util_lib.h> | ||
34 | |||
35 | struct MESSENGER_Application; | ||
36 | |||
37 | typedef struct UI_CHATS_Handle | ||
38 | { | ||
39 | WINDOW *window; | ||
40 | |||
41 | int line_index; | ||
42 | int line_offset; | ||
43 | int line_selected; | ||
44 | |||
45 | struct GNUNET_CHAT_Context *selected; | ||
46 | } UI_CHATS_Handle; | ||
47 | |||
48 | void | ||
49 | chats_event(UI_CHATS_Handle *chats, | ||
50 | struct MESSENGER_Application *app, | ||
51 | int key); | ||
52 | |||
53 | void | ||
54 | chats_print(UI_CHATS_Handle *chats, | ||
55 | struct MESSENGER_Application *app); | ||
56 | |||
57 | #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 @@ | |||
25 | #include "messages.h" | 25 | #include "messages.h" |
26 | 26 | ||
27 | #include "../application.h" | 27 | #include "../application.h" |
28 | #include "../util.h" | ||
29 | |||
30 | void | ||
31 | _messages_iterate(UI_MESSAGES_Handle *messages, | ||
32 | const struct GNUNET_CHAT_Message *message) | ||
33 | { | ||
34 | const bool selected = (messages->line_selected == messages->line_index); | ||
35 | |||
36 | messages->line_index++; | ||
37 | |||
38 | if (selected) | ||
39 | messages->selected = message; | ||
40 | } | ||
28 | 41 | ||
29 | void | 42 | void |
30 | messages_event(UI_MESSAGES_Handle *messages, | 43 | messages_event(UI_MESSAGES_Handle *messages, |
31 | struct MESSENGER_Application *app, | 44 | MESSENGER_Application *app, |
32 | int key) | 45 | int key) |
33 | { | 46 | { |
34 | // TODO | 47 | messages->line_index = 0; |
48 | messages->selected = NULL; | ||
49 | |||
50 | int count = 0; | ||
51 | |||
52 | UI_MESSAGES_List *element = messages->head; | ||
53 | while (element) | ||
54 | { | ||
55 | _messages_iterate(messages, element->message); | ||
56 | count++; | ||
57 | |||
58 | element = element->next; | ||
59 | } | ||
60 | |||
61 | switch (key) | ||
62 | { | ||
63 | case 27: | ||
64 | case KEY_EXIT: | ||
65 | { | ||
66 | app->chat.context = NULL; | ||
67 | break; | ||
68 | } | ||
69 | case KEY_UP: | ||
70 | { | ||
71 | messages->line_selected--; | ||
72 | break; | ||
73 | } | ||
74 | case KEY_DOWN: | ||
75 | { | ||
76 | messages->line_selected++; | ||
77 | break; | ||
78 | } | ||
79 | case '\n': | ||
80 | case KEY_ENTER: | ||
81 | { | ||
82 | if (messages->selected) | ||
83 | GNUNET_CHAT_message_delete( | ||
84 | messages->selected, | ||
85 | GNUNET_TIME_relative_get_zero_() | ||
86 | ); | ||
87 | |||
88 | break; | ||
89 | } | ||
90 | default: | ||
91 | break; | ||
92 | } | ||
93 | |||
94 | if (messages->line_selected < 0) | ||
95 | messages->line_selected = 0; | ||
96 | else if (messages->line_selected >= count) | ||
97 | messages->line_selected = count - 1; | ||
98 | |||
99 | if (!(messages->window)) | ||
100 | return; | ||
101 | |||
102 | const int height = getmaxy(messages->window) - getbegy(messages->window); | ||
103 | const int y = messages->line_selected - messages->line_offset; | ||
104 | |||
105 | if (y < 0) | ||
106 | messages->line_offset += y; | ||
107 | else if (y + 1 >= height) | ||
108 | messages->line_offset += y + 1 - height; | ||
109 | |||
110 | if (messages->line_offset < 0) | ||
111 | messages->line_offset = 0; | ||
112 | else if (messages->line_offset >= count) | ||
113 | messages->line_offset = count - 1; | ||
35 | } | 114 | } |
36 | 115 | ||
37 | int | 116 | void |
38 | _messages_iterate_print(void *cls, | 117 | _messages_iterate_print(UI_MESSAGES_Handle *messages, |
39 | struct GNUNET_CHAT_Context *context, | ||
40 | const struct GNUNET_CHAT_Message *message) | 118 | const struct GNUNET_CHAT_Message *message) |
41 | { | 119 | { |
42 | UI_MESSAGES_Handle *messages = cls; | 120 | const bool selected = (messages->line_selected == messages->line_index); |
121 | const int y = messages->line_index - messages->line_offset; | ||
122 | |||
123 | messages->line_index++; | ||
124 | |||
125 | if (y < 0) | ||
126 | return; | ||
43 | 127 | ||
44 | const int y = messages->line_index++; | 128 | const int height = getmaxy(messages->window) - getbegy(messages->window); |
129 | |||
130 | if (y >= height) | ||
131 | return; | ||
45 | 132 | ||
46 | enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); | 133 | enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); |
134 | struct GNUNET_CHAT_Contact *sender = GNUNET_CHAT_message_get_sender(message); | ||
135 | |||
136 | const char *name = sender? GNUNET_CHAT_contact_get_name(sender) : NULL; | ||
47 | const char *text = GNUNET_CHAT_message_get_text(message); | 137 | const char *text = GNUNET_CHAT_message_get_text(message); |
48 | 138 | ||
49 | struct GNUNET_TIME_Absolute timestamp = GNUNET_CHAT_message_get_timestamp( | 139 | struct GNUNET_TIME_Absolute timestamp = GNUNET_CHAT_message_get_timestamp( |
50 | message | 140 | message |
51 | ); | 141 | ); |
52 | 142 | ||
143 | const int attrs_select = A_BOLD; | ||
144 | |||
145 | if (selected) wattron(messages->window, attrs_select); | ||
146 | |||
53 | wmove(messages->window, y, 0); | 147 | wmove(messages->window, y, 0); |
54 | wprintw( | 148 | wprintw( |
55 | messages->window, | 149 | messages->window, |
56 | "%s | [%d]: %s", | 150 | "%s | [%d] %s: %s", |
57 | GNUNET_TIME_absolute2s(timestamp), | 151 | GNUNET_TIME_absolute2s(timestamp), |
58 | (int) kind, | 152 | (int) kind, |
153 | name, | ||
59 | text | 154 | text |
60 | ); | 155 | ); |
61 | 156 | ||
62 | return GNUNET_YES; | 157 | if (selected) wattroff(messages->window, attrs_select); |
63 | } | 158 | } |
64 | 159 | ||
65 | void | 160 | void |
66 | messages_print(UI_MESSAGES_Handle *messages, | 161 | messages_print(UI_MESSAGES_Handle *messages) |
67 | struct MESSENGER_Application *app) | ||
68 | { | 162 | { |
69 | if (!(messages->window)) | 163 | if (!(messages->window)) |
70 | return; | 164 | return; |
71 | 165 | ||
72 | struct GNUNET_CHAT_Context *context = app->chat.context; | ||
73 | |||
74 | messages->line_index = 0; | 166 | messages->line_index = 0; |
75 | GNUNET_CHAT_context_iterate_messages( | 167 | werase(messages->window); |
76 | context, | 168 | |
77 | _messages_iterate_print, | 169 | UI_MESSAGES_List *element = messages->head; |
78 | messages | 170 | while (element) |
171 | { | ||
172 | _messages_iterate_print(messages, element->message); | ||
173 | element = element->next; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | void | ||
178 | messages_clear(UI_MESSAGES_Handle *messages) | ||
179 | { | ||
180 | UI_MESSAGES_List *element; | ||
181 | while (messages->head) | ||
182 | { | ||
183 | element = messages->head; | ||
184 | |||
185 | GNUNET_CONTAINER_DLL_remove( | ||
186 | messages->head, | ||
187 | messages->tail, | ||
188 | element | ||
189 | ); | ||
190 | |||
191 | GNUNET_free(element); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | static int | ||
196 | _message_compare_timestamps(UNUSED void *cls, | ||
197 | UI_MESSAGES_List *list0, | ||
198 | UI_MESSAGES_List *list1) | ||
199 | { | ||
200 | struct GNUNET_TIME_Absolute time0, time1; | ||
201 | |||
202 | if ((!list0) || (!list1)) | ||
203 | return 0; | ||
204 | |||
205 | time0 = GNUNET_CHAT_message_get_timestamp(list0->message); | ||
206 | time1 = GNUNET_CHAT_message_get_timestamp(list1->message); | ||
207 | |||
208 | if (GNUNET_TIME_absolute_cmp(time0, >, time1)) | ||
209 | return -1; | ||
210 | else if (GNUNET_TIME_absolute_cmp(time0, <, time1)) | ||
211 | return +1; | ||
212 | else | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | void | ||
217 | messages_add(UI_MESSAGES_Handle *messages, | ||
218 | const struct GNUNET_CHAT_Message *message) | ||
219 | { | ||
220 | if (GNUNET_CHAT_KIND_DELETION == GNUNET_CHAT_message_get_kind(message)) | ||
221 | return; | ||
222 | |||
223 | UI_MESSAGES_List *element = GNUNET_new(UI_MESSAGES_List); | ||
224 | element->message = message; | ||
225 | |||
226 | GNUNET_CONTAINER_DLL_insert_sorted( | ||
227 | UI_MESSAGES_List, | ||
228 | _message_compare_timestamps, | ||
229 | NULL, | ||
230 | messages->head, | ||
231 | messages->tail, | ||
232 | element | ||
79 | ); | 233 | ); |
80 | } | 234 | } |
235 | |||
236 | void | ||
237 | messages_remove(UI_MESSAGES_Handle *messages, | ||
238 | const struct GNUNET_CHAT_Message *message) | ||
239 | { | ||
240 | UI_MESSAGES_List *element = messages->head; | ||
241 | while (element) | ||
242 | { | ||
243 | if (element->message == message) | ||
244 | break; | ||
245 | |||
246 | element = element->next; | ||
247 | } | ||
248 | |||
249 | if (element) | ||
250 | GNUNET_CONTAINER_DLL_remove( | ||
251 | messages->head, | ||
252 | messages->tail, | ||
253 | element | ||
254 | ); | ||
255 | } | ||
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 | |||
50 | UI_MESSAGES_List *tail; | 50 | UI_MESSAGES_List *tail; |
51 | 51 | ||
52 | int line_index; | 52 | int line_index; |
53 | int line_offset; | ||
54 | int line_selected; | ||
55 | |||
56 | const struct GNUNET_CHAT_Message *selected; | ||
53 | } UI_MESSAGES_Handle; | 57 | } UI_MESSAGES_Handle; |
54 | 58 | ||
55 | void | 59 | void |
56 | messages_event(UI_MESSAGES_Handle *messages, | 60 | messages_event(UI_MESSAGES_Handle *messages, |
57 | struct MESSENGER_Application *app, | 61 | struct MESSENGER_Application *app, |
58 | int key); | 62 | int key); |
59 | 63 | ||
60 | void | 64 | void |
61 | messages_print(UI_MESSAGES_Handle *messages, | 65 | messages_print(UI_MESSAGES_Handle *messages); |
62 | struct MESSENGER_Application *app); | 66 | |
67 | void | ||
68 | messages_clear(UI_MESSAGES_Handle *messages); | ||
69 | |||
70 | void | ||
71 | messages_add(UI_MESSAGES_Handle *messages, | ||
72 | const struct GNUNET_CHAT_Message *message); | ||
73 | |||
74 | void | ||
75 | messages_remove(UI_MESSAGES_Handle *messages, | ||
76 | const struct GNUNET_CHAT_Message *message); | ||
63 | 77 | ||
64 | #endif /* UI_MESSAGES_H_ */ | 78 | #endif /* UI_MESSAGES_H_ */ |
@@ -25,6 +25,8 @@ | |||
25 | #ifndef UTIL_H_ | 25 | #ifndef UTIL_H_ |
26 | #define UTIL_H_ | 26 | #define UTIL_H_ |
27 | 27 | ||
28 | #include <stdbool.h> | ||
29 | |||
28 | #define UNUSED __attribute__((unused)) | 30 | #define UNUSED __attribute__((unused)) |
29 | 31 | ||
30 | #endif /* UTIL_H_ */ | 32 | #endif /* UTIL_H_ */ |