diff options
author | TheJackiMonster <thejackimonster@gmail.com> | 2022-09-09 15:36:34 +0200 |
---|---|---|
committer | TheJackiMonster <thejackimonster@gmail.com> | 2022-09-09 15:36:34 +0200 |
commit | 2a72f770ecf2f6243fada17c6c31d4dd085eb911 (patch) | |
tree | 660d6b180b4a95f4967723cac252f8d4a1709bb9 | |
parent | 04b106bf09b8ef90418811ed583d1c4ebd5fdaf5 (diff) | |
download | messenger-cli-2a72f770ecf2f6243fada17c6c31d4dd085eb911.tar.gz messenger-cli-2a72f770ecf2f6243fada17c6c31d4dd085eb911.zip |
Added lines showing dates between chat messages
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r-- | src/ui/accounts.h | 3 | ||||
-rw-r--r-- | src/ui/chats.h | 3 | ||||
-rw-r--r-- | src/ui/list_input.h | 127 | ||||
-rw-r--r-- | src/ui/lobby_create_dialog.h | 3 | ||||
-rw-r--r-- | src/ui/members.h | 3 | ||||
-rw-r--r-- | src/ui/messages.c | 110 | ||||
-rw-r--r-- | src/ui/messages.h | 6 |
7 files changed, 160 insertions, 95 deletions
diff --git a/src/ui/accounts.h b/src/ui/accounts.h index fe0e1b1..4e278d5 100644 --- a/src/ui/accounts.h +++ b/src/ui/accounts.h | |||
@@ -40,6 +40,9 @@ typedef struct UI_ACCOUNTS_Handle | |||
40 | { | 40 | { |
41 | WINDOW *window; | 41 | WINDOW *window; |
42 | 42 | ||
43 | int line_prev; | ||
44 | int line_next; | ||
45 | |||
43 | int line_index; | 46 | int line_index; |
44 | int line_offset; | 47 | int line_offset; |
45 | int line_selected; | 48 | int line_selected; |
diff --git a/src/ui/chats.h b/src/ui/chats.h index db4e987..8e836bd 100644 --- a/src/ui/chats.h +++ b/src/ui/chats.h | |||
@@ -42,6 +42,9 @@ typedef struct UI_CHATS_Handle | |||
42 | { | 42 | { |
43 | WINDOW *window; | 43 | WINDOW *window; |
44 | 44 | ||
45 | int line_prev; | ||
46 | int line_next; | ||
47 | |||
45 | int line_index; | 48 | int line_index; |
46 | int line_offset; | 49 | int line_offset; |
47 | int line_selected; | 50 | int line_selected; |
diff --git a/src/ui/list_input.h b/src/ui/list_input.h index 932d0fd..717e1ba 100644 --- a/src/ui/list_input.h +++ b/src/ui/list_input.h | |||
@@ -29,80 +29,87 @@ | |||
29 | #include <stdlib.h> | 29 | #include <stdlib.h> |
30 | 30 | ||
31 | #define list_input_reset(list) { \ | 31 | #define list_input_reset(list) { \ |
32 | (list)->line_index = 0; \ | 32 | (list)->line_prev = 0; \ |
33 | (list)->selected = 0; \ | 33 | (list)->line_next = 0; \ |
34 | (list)->line_index = 0; \ | ||
35 | (list)->selected = 0; \ | ||
34 | } | 36 | } |
35 | 37 | ||
36 | #define list_input_select(list, line_width, item) { \ | 38 | #define list_input_select(list, line_width, item) { \ |
37 | const bool selected = ( \ | 39 | const bool selected = ( \ |
38 | ((list)->line_selected >= (list)->line_index) && \ | 40 | ((list)->line_selected >= (list)->line_index) && \ |
39 | ((list)->line_selected < (list)->line_index + line_width) \ | 41 | ((list)->line_selected < (list)->line_index + (line_width)) \ |
40 | ); \ | 42 | ); \ |
41 | \ | 43 | \ |
42 | (list)->line_index += line_width; \ | 44 | if ((!selected) && ((list)->line_selected > (list)->line_index)) \ |
43 | \ | 45 | (list)->line_prev = (list)->line_index; \ |
44 | if (selected) \ | 46 | \ |
45 | (list)->selected = item; \ | 47 | (list)->line_index += (line_width); \ |
48 | \ | ||
49 | if (selected) { \ | ||
50 | (list)->line_next = (list)->line_index; \ | ||
51 | (list)->selected = item; \ | ||
52 | } \ | ||
46 | } | 53 | } |
47 | 54 | ||
48 | #define list_input_event(list, key) { \ | 55 | #define list_input_event(list, key) { \ |
49 | int count = (list)->line_index; \ | 56 | int count = (list)->line_index; \ |
50 | \ | 57 | \ |
51 | switch (key) \ | 58 | switch (key) \ |
52 | { \ | 59 | { \ |
53 | case KEY_UP: \ | 60 | case KEY_UP: \ |
54 | { \ | 61 | { \ |
55 | (list)->line_selected--; \ | 62 | (list)->line_selected = (list)->line_prev; \ |
56 | break; \ | 63 | break; \ |
57 | } \ | 64 | } \ |
58 | case KEY_DOWN: \ | 65 | case KEY_DOWN: \ |
59 | { \ | 66 | { \ |
60 | (list)->line_selected++; \ | 67 | (list)->line_selected = (list)->line_next; \ |
61 | break; \ | 68 | break; \ |
62 | } \ | 69 | } \ |
63 | default: \ | 70 | default: \ |
64 | break; \ | 71 | break; \ |
65 | } \ | 72 | } \ |
66 | \ | 73 | \ |
67 | if ((list)->line_selected < 0) \ | 74 | if ((list)->line_selected < 0) \ |
68 | (list)->line_selected = 0; \ | 75 | (list)->line_selected = 0; \ |
69 | else if ((list)->line_selected >= count) \ | 76 | else if ((list)->line_selected >= count) \ |
70 | (list)->line_selected = count - 1; \ | 77 | (list)->line_selected = count - 1; \ |
71 | \ | 78 | \ |
72 | if ((list)->window) \ | 79 | if ((list)->window) \ |
73 | { \ | 80 | { \ |
74 | const int height = getmaxy((list)->window); \ | 81 | const int height = getmaxy((list)->window); \ |
75 | const int y = (list)->line_selected - (list)->line_offset; \ | 82 | const int y = (list)->line_selected - (list)->line_offset; \ |
76 | \ | 83 | \ |
77 | if (y < 0) \ | 84 | if (y < 0) \ |
78 | (list)->line_offset += y; \ | 85 | (list)->line_offset += y; \ |
79 | else if (y + 1 >= height) \ | 86 | else if (y + 1 >= height) \ |
80 | (list)->line_offset += y + 1 - height; \ | 87 | (list)->line_offset += y + 1 - height; \ |
81 | \ | 88 | \ |
82 | if ((list)->line_offset < 0) \ | 89 | if ((list)->line_offset < 0) \ |
83 | (list)->line_offset = 0; \ | 90 | (list)->line_offset = 0; \ |
84 | else if ((list)->line_offset >= count) \ | 91 | else if ((list)->line_offset >= count) \ |
85 | (list)->line_offset = count - 1; \ | 92 | (list)->line_offset = count - 1; \ |
86 | } \ | 93 | } \ |
87 | } | 94 | } |
88 | 95 | ||
89 | #define list_input_print_(list, line_width, yes_res, no_res) \ | 96 | #define list_input_print_(list, line_width, yes_res, no_res) \ |
90 | const bool selected = ( \ | 97 | const bool selected = ( \ |
91 | ((list)->line_selected >= (list)->line_index) && \ | 98 | ((list)->line_selected >= (list)->line_index) && \ |
92 | ((list)->line_selected < (list)->line_index + line_width) \ | 99 | ((list)->line_selected < (list)->line_index + (line_width)) \ |
93 | ); \ | 100 | ); \ |
94 | \ | 101 | \ |
95 | const int y = (list)->line_index - (list)->line_offset; { \ | 102 | const int y = (list)->line_index - (list)->line_offset; { \ |
96 | \ | 103 | \ |
97 | (list)->line_index += line_width; \ | 104 | (list)->line_index += (line_width); \ |
98 | \ | 105 | \ |
99 | if (y + line_width < 1) \ | 106 | if (y + (line_width) < 1) \ |
100 | return yes_res; \ | 107 | return yes_res; \ |
101 | \ | 108 | \ |
102 | const int height = getmaxy((list)->window); \ | 109 | const int height = getmaxy((list)->window); \ |
103 | \ | 110 | \ |
104 | if (y >= height) \ | 111 | if (y >= height) \ |
105 | return no_res; \ | 112 | return no_res; \ |
106 | } | 113 | } |
107 | 114 | ||
108 | #define list_input_print_gnunet(list, line_width) \ | 115 | #define list_input_print_gnunet(list, line_width) \ |
diff --git a/src/ui/lobby_create_dialog.h b/src/ui/lobby_create_dialog.h index bdc34da..1497255 100644 --- a/src/ui/lobby_create_dialog.h +++ b/src/ui/lobby_create_dialog.h | |||
@@ -39,6 +39,9 @@ typedef struct UI_LOBBY_CREATE_DIALOG_Handle | |||
39 | WINDOW *window; | 39 | WINDOW *window; |
40 | WINDOW **win; | 40 | WINDOW **win; |
41 | 41 | ||
42 | int line_prev; | ||
43 | int line_next; | ||
44 | |||
42 | int line_index; | 45 | int line_index; |
43 | int line_offset; | 46 | int line_offset; |
44 | int line_selected; | 47 | int line_selected; |
diff --git a/src/ui/members.h b/src/ui/members.h index 6e8711b..62c564f 100644 --- a/src/ui/members.h +++ b/src/ui/members.h | |||
@@ -50,6 +50,9 @@ typedef struct UI_MEMBERS_Handle | |||
50 | UI_MEMBERS_List *head; | 50 | UI_MEMBERS_List *head; |
51 | UI_MEMBERS_List *tail; | 51 | UI_MEMBERS_List *tail; |
52 | 52 | ||
53 | int line_prev; | ||
54 | int line_next; | ||
55 | |||
53 | int line_index; | 56 | int line_index; |
54 | int line_offset; | 57 | int line_offset; |
55 | int line_selected; | 58 | int line_selected; |
diff --git a/src/ui/messages.c b/src/ui/messages.c index 86df8e5..7b2d724 100644 --- a/src/ui/messages.c +++ b/src/ui/messages.c | |||
@@ -29,6 +29,26 @@ | |||
29 | #include "../application.h" | 29 | #include "../application.h" |
30 | #include "../util.h" | 30 | #include "../util.h" |
31 | 31 | ||
32 | struct tm* | ||
33 | _messages_new_day(time_t* current_time, | ||
34 | const time_t* timestamp) | ||
35 | { | ||
36 | struct tm* ts = localtime(timestamp); | ||
37 | |||
38 | ts->tm_sec = 0; | ||
39 | ts->tm_min = 0; | ||
40 | ts->tm_hour = 0; | ||
41 | |||
42 | const time_t date_time = timelocal(ts); | ||
43 | |||
44 | if (date_time <= *current_time) { | ||
45 | return NULL; | ||
46 | } | ||
47 | |||
48 | *current_time = date_time; | ||
49 | return ts; | ||
50 | } | ||
51 | |||
32 | void | 52 | void |
33 | _messages_handle_message(UI_MESSAGES_Handle *messages) | 53 | _messages_handle_message(UI_MESSAGES_Handle *messages) |
34 | { | 54 | { |
@@ -65,11 +85,17 @@ messages_event(UI_MESSAGES_Handle *messages, | |||
65 | int key) | 85 | int key) |
66 | { | 86 | { |
67 | list_input_reset(messages); | 87 | list_input_reset(messages); |
88 | messages->line_time = 0; | ||
68 | 89 | ||
69 | UI_MESSAGES_List *element = messages->head; | 90 | UI_MESSAGES_List *element = messages->head; |
70 | while (element) | 91 | while (element) |
71 | { | 92 | { |
72 | list_input_select(messages, 1, element->message); | 93 | struct tm *ts = _messages_new_day( |
94 | &(messages->line_time), | ||
95 | &(element->timestamp) | ||
96 | ); | ||
97 | |||
98 | list_input_select(messages, ts? 2 : 1, element->message); | ||
73 | element = element->next; | 99 | element = element->next; |
74 | } | 100 | } |
75 | 101 | ||
@@ -113,12 +139,11 @@ messages_event(UI_MESSAGES_Handle *messages, | |||
113 | 139 | ||
114 | void | 140 | void |
115 | _messages_iterate_print(UI_MESSAGES_Handle *messages, | 141 | _messages_iterate_print(UI_MESSAGES_Handle *messages, |
142 | const time_t* timestamp, | ||
116 | const struct GNUNET_CHAT_Message *message) | 143 | const struct GNUNET_CHAT_Message *message) |
117 | { | 144 | { |
118 | enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); | 145 | enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); |
119 | 146 | ||
120 | list_input_print(messages, 1); | ||
121 | |||
122 | struct GNUNET_CHAT_Contact *sender = GNUNET_CHAT_message_get_sender(message); | 147 | struct GNUNET_CHAT_Contact *sender = GNUNET_CHAT_message_get_sender(message); |
123 | 148 | ||
124 | const char *name = sender? GNUNET_CHAT_contact_get_name(sender) : NULL; | 149 | const char *name = sender? GNUNET_CHAT_contact_get_name(sender) : NULL; |
@@ -126,29 +151,35 @@ _messages_iterate_print(UI_MESSAGES_Handle *messages, | |||
126 | 151 | ||
127 | const struct GNUNET_CHAT_File *file = GNUNET_CHAT_message_get_file(message); | 152 | const struct GNUNET_CHAT_File *file = GNUNET_CHAT_message_get_file(message); |
128 | 153 | ||
129 | struct GNUNET_TIME_Absolute abs_time = GNUNET_CHAT_message_get_timestamp( | 154 | struct tm* ts = localtime(timestamp); |
130 | message | 155 | char time_buf [255]; |
131 | ); | ||
132 | 156 | ||
133 | struct GNUNET_TIME_Timestamp timestamp = GNUNET_TIME_absolute_to_timestamp( | 157 | strftime(time_buf, sizeof(time_buf), "%H:%M", ts); |
134 | abs_time | ||
135 | ); | ||
136 | 158 | ||
137 | const time_t s_after_epoch = ( | 159 | ts = _messages_new_day(&(messages->line_time), timestamp); |
138 | GNUNET_TIME_timestamp_to_s(timestamp) | ||
139 | ); | ||
140 | 160 | ||
141 | struct tm* ts = localtime(&s_after_epoch); | 161 | list_input_print(messages, ts? 2 : 1); |
142 | char time_buf [255]; | 162 | wmove(messages->window, y, 0); |
143 | 163 | ||
144 | strftime(time_buf, sizeof(time_buf), "%H:%M", ts); | 164 | if (ts) { |
165 | char date_buf [255]; | ||
166 | |||
167 | strftime(date_buf, sizeof(date_buf), "%x", ts); | ||
168 | |||
169 | const int width = getmaxx(messages->window); | ||
170 | |||
171 | whline(messages->window, '-', width); | ||
172 | wmove(messages->window, y, 8); | ||
173 | |||
174 | wprintw(messages->window, " %s ", date_buf); | ||
175 | wmove(messages->window, y+1, 0); | ||
176 | } | ||
145 | 177 | ||
146 | const int attrs_select = A_BOLD; | 178 | const int attrs_select = A_BOLD; |
147 | 179 | ||
148 | if (selected) wattron(messages->window, attrs_select); | 180 | if (selected) wattron(messages->window, attrs_select); |
149 | 181 | ||
150 | wmove(messages->window, y, 0); | 182 | wprintw(messages->window, " %s | ", time_buf); |
151 | wprintw(messages->window, "%s | ", time_buf); | ||
152 | 183 | ||
153 | switch (kind) { | 184 | switch (kind) { |
154 | case GNUNET_CHAT_KIND_JOIN: | 185 | case GNUNET_CHAT_KIND_JOIN: |
@@ -207,7 +238,6 @@ _messages_iterate_print(UI_MESSAGES_Handle *messages, | |||
207 | break; | 238 | break; |
208 | } | 239 | } |
209 | 240 | ||
210 | |||
211 | if (selected) wattroff(messages->window, attrs_select); | 241 | if (selected) wattroff(messages->window, attrs_select); |
212 | } | 242 | } |
213 | 243 | ||
@@ -218,12 +248,14 @@ messages_print(UI_MESSAGES_Handle *messages) | |||
218 | return; | 248 | return; |
219 | 249 | ||
220 | list_input_reset(messages); | 250 | list_input_reset(messages); |
251 | messages->line_time = 0; | ||
252 | |||
221 | werase(messages->window); | 253 | werase(messages->window); |
222 | 254 | ||
223 | UI_MESSAGES_List *element = messages->head; | 255 | UI_MESSAGES_List *element = messages->head; |
224 | while (element) | 256 | while (element) |
225 | { | 257 | { |
226 | _messages_iterate_print(messages, element->message); | 258 | _messages_iterate_print(messages, &(element->timestamp), element->message); |
227 | element = element->next; | 259 | element = element->next; |
228 | } | 260 | } |
229 | 261 | ||
@@ -278,17 +310,12 @@ _message_compare_timestamps(UNUSED void *cls, | |||
278 | UI_MESSAGES_List *list0, | 310 | UI_MESSAGES_List *list0, |
279 | UI_MESSAGES_List *list1) | 311 | UI_MESSAGES_List *list1) |
280 | { | 312 | { |
281 | struct GNUNET_TIME_Absolute time0, time1; | ||
282 | |||
283 | if ((!list0) || (!list1)) | 313 | if ((!list0) || (!list1)) |
284 | return 0; | 314 | return 0; |
285 | 315 | ||
286 | time0 = GNUNET_CHAT_message_get_timestamp(list0->message); | 316 | if (list0->timestamp > list1->timestamp) |
287 | time1 = GNUNET_CHAT_message_get_timestamp(list1->message); | ||
288 | |||
289 | if (GNUNET_TIME_absolute_cmp(time0, >, time1)) | ||
290 | return -1; | 317 | return -1; |
291 | else if (GNUNET_TIME_absolute_cmp(time0, <, time1)) | 318 | else if (list0->timestamp < list1->timestamp) |
292 | return +1; | 319 | return +1; |
293 | else | 320 | else |
294 | return 0; | 321 | return 0; |
@@ -309,19 +336,33 @@ messages_add(UI_MESSAGES_Handle *messages, | |||
309 | break; | 336 | break; |
310 | } | 337 | } |
311 | 338 | ||
312 | const int height = getmaxy(messages->window); | 339 | list_input_reset(messages); |
313 | const int line_height = height - 2; | 340 | messages->line_time = 0; |
314 | |||
315 | int count = 0; | ||
316 | 341 | ||
317 | UI_MESSAGES_List *element = messages->head; | 342 | UI_MESSAGES_List *element = messages->head; |
318 | while (element) | 343 | while (element) |
319 | { | 344 | { |
320 | count++; | 345 | struct tm *ts = _messages_new_day( |
346 | &(messages->line_time), | ||
347 | &(element->timestamp) | ||
348 | ); | ||
349 | |||
350 | list_input_select(messages, ts? 2 : 1, element->message); | ||
321 | element = element->next; | 351 | element = element->next; |
322 | } | 352 | } |
323 | 353 | ||
354 | list_input_select(messages, 1, NULL); | ||
355 | |||
356 | const struct GNUNET_TIME_Absolute abs_time = ( | ||
357 | GNUNET_CHAT_message_get_timestamp(message) | ||
358 | ); | ||
359 | |||
360 | const struct GNUNET_TIME_Timestamp timestamp = ( | ||
361 | GNUNET_TIME_absolute_to_timestamp(abs_time) | ||
362 | ); | ||
363 | |||
324 | element = GNUNET_new(UI_MESSAGES_List); | 364 | element = GNUNET_new(UI_MESSAGES_List); |
365 | element->timestamp = GNUNET_TIME_timestamp_to_s(timestamp); | ||
325 | element->message = message; | 366 | element->message = message; |
326 | 367 | ||
327 | GNUNET_CONTAINER_DLL_insert_sorted( | 368 | GNUNET_CONTAINER_DLL_insert_sorted( |
@@ -333,11 +374,10 @@ messages_add(UI_MESSAGES_Handle *messages, | |||
333 | element | 374 | element |
334 | ); | 375 | ); |
335 | 376 | ||
336 | if (messages->line_selected >= count) | 377 | list_input_select(messages, 1, NULL); |
337 | messages->line_selected = count + 1; | ||
338 | 378 | ||
339 | if ((line_height > 0) && (messages->line_offset + line_height >= count)) | 379 | if (!(messages->selected)) |
340 | messages->line_offset = count + 1 - line_height; | 380 | list_input_event(messages, KEY_DOWN); |
341 | } | 381 | } |
342 | 382 | ||
343 | void | 383 | void |
diff --git a/src/ui/messages.h b/src/ui/messages.h index 166941a..685cb82 100644 --- a/src/ui/messages.h +++ b/src/ui/messages.h | |||
@@ -36,6 +36,8 @@ struct MESSENGER_Application; | |||
36 | 36 | ||
37 | typedef struct UI_MESSAGES_List | 37 | typedef struct UI_MESSAGES_List |
38 | { | 38 | { |
39 | time_t timestamp; | ||
40 | |||
39 | const struct GNUNET_CHAT_Message *message; | 41 | const struct GNUNET_CHAT_Message *message; |
40 | 42 | ||
41 | struct UI_MESSAGES_List *prev; | 43 | struct UI_MESSAGES_List *prev; |
@@ -51,9 +53,13 @@ typedef struct UI_MESSAGES_Handle | |||
51 | UI_MESSAGES_List *head; | 53 | UI_MESSAGES_List *head; |
52 | UI_MESSAGES_List *tail; | 54 | UI_MESSAGES_List *tail; |
53 | 55 | ||
56 | int line_prev; | ||
57 | int line_next; | ||
58 | |||
54 | int line_index; | 59 | int line_index; |
55 | int line_offset; | 60 | int line_offset; |
56 | int line_selected; | 61 | int line_selected; |
62 | time_t line_time; | ||
57 | 63 | ||
58 | const struct GNUNET_CHAT_Message *selected; | 64 | const struct GNUNET_CHAT_Message *selected; |
59 | 65 | ||