1 #include "friend.h"
2
3 #include "settings.h"
4 #include "sidebar.h"
5
6 #include "../avatar.h"
7 #include "../debug.h"
8 #include "../flist.h"
9 #include "../friend.h"
10 #include "../macros.h"
11 #include "../settings.h"
12 #include "../theme.h"
13 #include "../tox.h"
14
15 #include "../native/dialog.h"
16
17 #include "../ui/draw.h"
18 #include "../ui/edit.h"
19 #include "../ui/scrollable.h"
20 #include "../ui/svg.h"
21 #include "../ui/text.h"
22
23 #include "../main.h" // add friend status // TODO this is stupid wrong
24
25 #include <string.h>
26
27 /* Header for friend chat window */
draw_friend(int x,int y,int w,int height)28 static void draw_friend(int x, int y, int w, int height) {
29 FRIEND *f = flist_get_friend();
30 if (!f) {
31 LOG_ERR("Friend", "Could not get selected friend.\n");
32 return;
33 }
34
35 // draw avatar or default image
36 if (friend_has_avatar(f)) {
37 draw_avatar_image(f->avatar->img, x + SCALE(10), SCALE(10), f->avatar->width, f->avatar->height,
38 BM_CONTACT_WIDTH, BM_CONTACT_WIDTH);
39 } else {
40 drawalpha(BM_CONTACT, x + SCALE(10), SCALE(10), BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, COLOR_MAIN_TEXT);
41 }
42
43 setcolor(COLOR_MAIN_TEXT);
44 setfont(FONT_TITLE);
45
46 if (f->alias) {
47 drawtextrange(x + SCALE(60), settings.window_width - SCALE(128), SCALE(18), f->alias, f->alias_length);
48 } else {
49 drawtextrange(x + SCALE(60), settings.window_width - SCALE(128), SCALE(18), f->name, f->name_length);
50 }
51
52 setcolor(COLOR_MAIN_TEXT_SUBTEXT);
53 setfont(FONT_STATUS);
54 drawtextrange(x + SCALE(60), settings.window_width - SCALE(128), SCALE(32), f->status_message,
55 f->status_length);
56
57 if (f->typing) {
58 int typing_y = ((y + height) + SCALE(CHAT_BOX_TOP - 14));
59 setfont(FONT_MISC);
60 // @TODO: separate these colors if needed
61 setcolor(COLOR_MAIN_TEXT_HINT);
62 if (f->alias) {
63 drawtextwidth_right(x, SCALE(MESSAGES_X - NAME_OFFSET - 16), typing_y, f->alias, f->alias_length);
64 } else {
65 drawtextwidth_right(x, SCALE(MESSAGES_X - NAME_OFFSET - 16), typing_y, f->name, f->name_length);
66 }
67 drawtextwidth(x + SCALE(MESSAGES_X - 18), x + w, typing_y, S(IS_TYPING), SLEN(IS_TYPING));
68 }
69 }
70
71 /* Draw an invite to be a friend window */
draw_friend_request(int x,int y,int w,int h)72 static void draw_friend_request(int x, int y, int w, int h) {
73 FREQUEST *req = flist_get_frequest();
74 if (!req) {
75 LOG_ERR("Layout Friend", "Unable to draw a friend request without a friend request.");
76 return;
77 }
78
79 setcolor(COLOR_MAIN_TEXT);
80 setfont(FONT_SELF_NAME);
81 drawstr(x + SCALE(10), SCALE(20), FRIENDREQUEST);
82
83 if (req->msg && req->length) {
84 setfont(FONT_TEXT);
85 utox_draw_text_multiline_within_box(x + SCALE(10), y + SCALE(70), w + x, y, y + h, font_small_lineheight,
86 req->msg, req->length, ~0, ~0, 0, 0, true);
87 }
88 }
89
draw_friend_settings(int x,int y,int UNUSED (width),int UNUSED (height))90 static void draw_friend_settings(int x, int y, int UNUSED(width), int UNUSED(height)) {
91 setcolor(COLOR_MAIN_TEXT);
92 setfont(FONT_SELF_NAME);
93
94 drawstr(x + SCALE(10), y + SCALE(MAIN_TOP + 10), FRIEND_PUBLIC_KEY);
95 drawstr(x + SCALE(10), y + SCALE(MAIN_TOP + 60), FRIEND_ALIAS);
96 drawstr(x + SCALE(20) + BM_SWITCH_WIDTH, y + SCALE(MAIN_TOP + 112), FRIEND_AUTOACCEPT);
97 }
98
draw_friend_deletion(int x,int UNUSED (y),int UNUSED (w),int UNUSED (height))99 static void draw_friend_deletion(int x, int UNUSED(y), int UNUSED(w), int UNUSED(height)) {
100 FRIEND *f = flist_get_friend();
101 if (!f) {
102 LOG_ERR("Friend", "Could not get selected friend.");
103 return;
104 }
105
106 setcolor(COLOR_MAIN_TEXT);
107 setfont(FONT_SELF_NAME);
108
109 int length = f->name_length + 2;
110 char str[length];
111 snprintf(str, length, "%.*s?", (int)f->name_length, f->name);
112
113 const int push = UTOX_STR_WIDTH(DELETE_MESSAGE);
114 drawstr(x + SCALE(10), SCALE(70), DELETE_MESSAGE);
115 drawtextrange(push + x + SCALE(10), settings.window_width, SCALE(70), str, length - 1);
116 }
117
118 /* Draw add a friend window */
draw_add_friend(int x,int UNUSED (y),int UNUSED (w),int height)119 static void draw_add_friend(int x, int UNUSED(y), int UNUSED(w), int height) {
120 setcolor(COLOR_MAIN_TEXT);
121 setfont(FONT_SELF_NAME);
122 drawstr(x + SCALE(10), SCALE(20), ADDFRIENDS);
123
124 setcolor(COLOR_MAIN_TEXT_SUBTEXT);
125 setfont(FONT_TEXT);
126 drawstr(x + SCALE(10), SCALE(MAIN_TOP + 10), TOXID);
127
128 drawstr(x + SCALE(10), SCALE(MAIN_TOP + 58), MESSAGE);
129
130 if (!addfriend_status) {
131 return;
132 }
133
134 setfont(FONT_MISC);
135 setcolor(C_RED);
136
137 STRING *str;
138
139 switch (addfriend_status) {
140 case ADDF_SENT:
141 str = SPTR(REQ_SENT);
142 break;
143 case ADDF_BADNAME:
144 str = SPTR(REQ_INVALID_ID);
145 break;
146 case ADDF_NONAME:
147 str = SPTR(REQ_EMPTY_ID);
148 break;
149 case ADDF_TOOLONG: // if message length is too long.
150 str = SPTR(REQ_LONG_MSG);
151 break;
152 case ADDF_NOMESSAGE: // if no message (message length must be >= 1 byte).
153 str = SPTR(REQ_NO_MSG);
154 break;
155 case ADDF_OWNKEY: // if user's own key.
156 str = SPTR(REQ_SELF_ID);
157 break;
158 case ADDF_ALREADYSENT: // if friend request already sent or already a friend.
159 str = SPTR(REQ_ALREADY_FRIENDS);
160 break;
161 case ADDF_BADCHECKSUM: // if bad checksum in address.
162 str = SPTR(REQ_BAD_CHECKSUM);
163 break;
164 case ADDF_SETNEWNOSPAM: // if the friend was already there but the nospam was different.
165 str = SPTR(REQ_BAD_NOSPAM);
166 break;
167 case ADDF_NOMEM: // if increasing the friend list size fails.
168 str = SPTR(REQ_NO_MEMORY);
169 break;
170 case ADDF_NOFREQUESTSENT:
171 str = SPTR(REQ_ADDED_NO_FREQ_SENT);
172 break;
173 case ADDF_UNKNOWN: // for unknown error.
174 case ADDF_NONE: // this case must never be rendered, but if it does, assume it's an error
175 default:
176 str = SPTR(REQ_UNKNOWN);
177 break;
178 }
179
180 utox_draw_text_multiline_within_box(x + SCALE(10), MAIN_TOP + SCALE(166),
181 settings.window_width - BM_SBUTTON_WIDTH - SCALE(10), 0, height,
182 font_small_lineheight, str->str, str->length, 0xFFFF, 0, 0, 0, 1);
183 }
184
185 SCROLLABLE scrollbar_friend = {
186 .panel = { .type = PANEL_SCROLLABLE, },
187 .color = C_SCROLL,
188 };
189
190 PANEL messages_friend = {
191 .type = PANEL_MESSAGES,
192 .content_scroll = &scrollbar_friend,
193 };
194
195 PANEL
196 panel_friend = {
197 .type = PANEL_NONE,
198 .disabled = 1,
199 .child = (PANEL*[]) {
200 &panel_friend_chat,
201 &panel_friend_video,
202 &panel_friend_settings,
203 &panel_friend_confirm_deletion,
204 NULL
205 }
206 },
207 panel_friend_chat = {
208 .type = PANEL_NONE,
209 .disabled = 0,
210 .drawfunc = draw_friend,
211 .child = (PANEL*[]) {
212 (PANEL*)&scrollbar_friend,
213 (PANEL*)&edit_chat_msg_friend, // this needs to be one of the first, to get events before the others
214 (PANEL*)&messages_friend,
215 (PANEL*)&button_call_decline,
216 (PANEL*)&button_call_audio,
217 (PANEL*)&button_call_video,
218 (PANEL*)&button_send_file,
219 (PANEL*)&button_send_screenshot,
220 (PANEL*)&button_chat_send_friend,
221 NULL
222 }
223 },
224 panel_friend_video = {
225 .type = PANEL_INLINE_VIDEO,
226 .disabled = 1,
227 .child = (PANEL*[]) {
228 NULL
229 }
230 },
231 panel_friend_settings = {
232 .type = PANEL_NONE,
233 .disabled = 1,
234 .drawfunc = draw_friend_settings,
235 .child = (PANEL*[]) {
236 (PANEL*)&edit_friend_pubkey,
237 (PANEL*)&edit_friend_alias,
238 (PANEL*)&switch_friend_autoaccept_ft,
239 (PANEL*)&button_export_chatlog,
240 NULL
241 }
242 },
243 panel_friend_confirm_deletion = {
244 .type = PANEL_NONE,
245 .disabled = true,
246 .drawfunc = draw_friend_deletion,
247 .child = (PANEL*[]) {
248 (PANEL *)&button_confirm_deletion,
249 (PANEL *)&button_deny_deletion,
250 NULL
251 }
252
253 },
254 panel_friend_request = {
255 .type = PANEL_NONE,
256 .disabled = 1,
257 .drawfunc = draw_friend_request,
258 .child = (PANEL*[]) {
259 (PANEL*)&button_accept_friend,
260 (PANEL*)&button_ignore_friend,
261 NULL
262 }
263 },
264 panel_add_friend = {
265 .type = PANEL_NONE,
266 .disabled = 1,
267 .drawfunc = draw_add_friend,
268 .child = (PANEL*[]) {
269 (PANEL*)&button_send_friend_request,
270 (PANEL*)&edit_add_new_friend_id,
271 (PANEL*)&edit_add_new_friend_msg,
272 NULL
273 }
274 };
275
button_add_new_contact_on_mup(void)276 static void button_add_new_contact_on_mup(void) {
277 if (tox_thread_init == UTOX_TOX_THREAD_INIT_SUCCESS) {
278 /* Only change if we're logged in! */
279 edit_setstr(&edit_add_new_friend_id, (char *)edit_search.data, edit_search.length);
280 edit_setstr(&edit_search, (char *)"", 0);
281 flist_selectaddfriend();
282 edit_setfocus(&edit_add_new_friend_msg);
283 }
284 }
285
button_send_friend_request_on_mup(void)286 static void button_send_friend_request_on_mup(void) {
287 friend_add(edit_add_new_friend_id.data, edit_add_new_friend_id.length, edit_add_new_friend_msg.data, edit_add_new_friend_msg.length);
288 edit_resetfocus();
289 }
290
291 #include "../tox.h"
292
button_call_decline_on_mup(void)293 static void button_call_decline_on_mup(void) {
294 FRIEND *f = flist_get_friend();
295 if (!f) {
296 LOG_ERR("Friend", "Could not get selected friend.");
297 return;
298 }
299
300 if (f->call_state_friend) {
301 LOG_TRACE("Layout Friend", "Declining call: %u", f->number);
302 postmessage_toxcore(TOX_CALL_DISCONNECT, f->number, 0, NULL);
303 }
304 }
305
306 #include "../av/utox_av.h"
307 #include "../av/audio.h"
308 #include "../ui/button.h"
button_call_decline_update(BUTTON * b)309 static void button_call_decline_update(BUTTON *b) {
310 FRIEND *f = flist_get_friend();
311 if (!f) {
312 LOG_ERR("Friend", "Could not get selected friend.");
313 return;
314 }
315
316 if (UTOX_AVAILABLE_AUDIO(f->number) && !UTOX_SENDING_AUDIO(f->number)) {
317 button_setcolors_danger(b);
318 b->nodraw = b->disabled = b->panel.disabled = false;
319 } else {
320 button_setcolors_disabled(b);
321 b->nodraw = b->disabled = b->panel.disabled = true;
322 }
323 }
324
button_call_audio_on_mup(void)325 static void button_call_audio_on_mup(void) {
326 FRIEND *f = flist_get_friend();
327 if (!f) {
328 LOG_ERR("Friend", "Could not get selected friend.");
329 return;
330 }
331
332 if (f->call_state_self) {
333 if (UTOX_SENDING_AUDIO(f->number)) {
334 LOG_TRACE("Layout Friend", "Ending call: %u", f->number);
335 /* var 3/4 = bool send video */
336 postmessage_toxcore(TOX_CALL_DISCONNECT, f->number, 0, NULL);
337 } else {
338 LOG_TRACE("Layout Friend", "Canceling call: friend = %d", f->number);
339 postmessage_toxcore(TOX_CALL_DISCONNECT, f->number, 0, NULL);
340 }
341 } else if (UTOX_AVAILABLE_AUDIO(f->number)) {
342 LOG_TRACE("Layout Friend", "Accept Call: %u", f->number);
343 postmessage_toxcore(TOX_CALL_ANSWER, f->number, 0, NULL);
344 } else if (f->online) {
345 postmessage_toxcore(TOX_CALL_SEND, f->number, 0, NULL);
346 LOG_TRACE("Layout Friend", "Calling friend: %u", f->number);
347 }
348 }
349
button_call_audio_update(BUTTON * b)350 static void button_call_audio_update(BUTTON *b) {
351 FRIEND *f = flist_get_friend();
352 if (!f) {
353 LOG_ERR("Friend", "Could not get selected friend.");
354 return;
355 }
356
357 if (UTOX_SENDING_AUDIO(f->number)) {
358 button_setcolors_danger(b);
359 b->disabled = false;
360 } else if (UTOX_AVAILABLE_AUDIO(f->number)) {
361 button_setcolors_warning(b);
362 b->disabled = false;
363 } else {
364 if (f->online) {
365 button_setcolors_success(b);
366 b->disabled = false;
367 } else {
368 button_setcolors_disabled(b);
369 b->disabled = true;
370 }
371 }
372 }
373
374 #include "../av/video.h"
button_call_video_on_mup(void)375 static void button_call_video_on_mup(void) {
376 FRIEND *f = flist_get_friend();
377 if (!f) {
378 LOG_ERR("Friend", "Could not get selected friend.");
379 return;
380 }
381
382 if (f->call_state_self) {
383 if (SELF_ACCEPT_VIDEO(f->number)) {
384 LOG_TRACE("Layout Friend", "Canceling call (video): %u", f->number);
385 postmessage_toxcore(TOX_CALL_PAUSE_VIDEO, f->number, 1, NULL);
386 } else if (UTOX_SENDING_AUDIO(f->number)) {
387 LOG_TRACE("Layout Friend", "Audio call inprogress, adding video");
388 postmessage_toxcore(TOX_CALL_RESUME_VIDEO, f->number, 1, NULL);
389 } else {
390 LOG_TRACE("Layout Friend", "Ending call (video): %u", f->number);
391 postmessage_toxcore(TOX_CALL_DISCONNECT, f->number, 1, NULL);
392 }
393 } else if (f->call_state_friend) {
394 LOG_TRACE("Layout Friend", "Accept Call (video): %u %u", f->number, f->call_state_friend);
395 postmessage_toxcore(TOX_CALL_ANSWER, f->number, 1, NULL);
396 } else if (f->online) {
397 postmessage_toxcore(TOX_CALL_SEND, f->number, 1, NULL);
398 LOG_TRACE("Layout Friend", "Calling friend (video): %u", f->number);
399 }
400 }
401
button_call_video_update(BUTTON * b)402 static void button_call_video_update(BUTTON *b) {
403 FRIEND *f = flist_get_friend();
404 if (!f) {
405 LOG_ERR("Friend", "Could not get selected friend.");
406 return;
407 }
408
409 if (SELF_SEND_VIDEO(f->number)) {
410 button_setcolors_danger(b);
411 b->disabled = false;
412 } else if (FRIEND_SENDING_VIDEO(f->number)) {
413 button_setcolors_warning(b);
414 b->disabled = false;
415 } else {
416 if (f->online) {
417 button_setcolors_success(b);
418 b->disabled = false;
419 } else {
420 button_setcolors_disabled(b);
421 b->disabled = true;
422 }
423 }
424 }
425
button_accept_friend_on_mup(void)426 static void button_accept_friend_on_mup(void) {
427 FREQUEST *req = flist_get_frequest();
428 postmessage_toxcore(TOX_FRIEND_ACCEPT, 0, 0, req);
429 panel_friend_request.disabled = true;
430 }
431
button_ignore_friend_on_mup(void)432 static void button_ignore_friend_on_mup(void){
433 FREQUEST *req = flist_get_frequest();
434 if (!req) {
435 LOG_ERR("Friend", "Could not get selected friend request");
436 return;
437 }
438
439 flist_delete_sitem();
440 panel_friend_request.disabled = true;
441 }
442
button_menu_update(BUTTON * b)443 static void button_menu_update(BUTTON *b) {
444 b->c1 = COLOR_BKGRND_MENU;
445 b->c2 = COLOR_BKGRND_MENU_HOVER;
446 b->c3 = COLOR_BKGRND_MENU_ACTIVE;
447 b->ct1 = COLOR_MENU_TEXT;
448 b->ct2 = COLOR_MENU_TEXT;
449 if (b->mousedown || b->disabled) {
450 b->ct1 = COLOR_MENU_TEXT_ACTIVE;
451 b->ct2 = COLOR_MENU_TEXT_ACTIVE;
452 }
453 b->cd = COLOR_BKGRND_MENU_ACTIVE;
454 }
455
456 BUTTON button_add_new_contact = {
457 .panel = {
458 .type = PANEL_BUTTON,
459 .x = SIDEBAR_BUTTON_LEFT,
460 .y = ROSTER_BOTTOM,
461 .width = SIDEBAR_BUTTON_WIDTH,
462 .height = SIDEBAR_BUTTON_HEIGHT,
463 },
464 .bm_icon = BM_ADD,
465 .icon_w = _BM_ADD_WIDTH,
466 .icon_h = _BM_ADD_WIDTH,
467 .update = button_menu_update,
468 .on_mup = button_add_new_contact_on_mup,
469 .disabled = true,
470 .nodraw = true,
471 .tooltip_text = {.i18nal = STR_ADDFRIENDS },
472 };
473
474 BUTTON button_send_friend_request = {
475 .panel = {
476 .type = PANEL_BUTTON,
477 .x = -10 - _BM_SBUTTON_WIDTH,
478 .y = MAIN_TOP + 168,
479 .width = _BM_SBUTTON_WIDTH,
480 .height = _BM_SBUTTON_HEIGHT,
481 },
482 .bm_fill = BM_SBUTTON,
483 .button_text = {.i18nal = STR_ADD },
484 .update = button_setcolors_success,
485 .on_mup = button_send_friend_request_on_mup,
486 .disabled = false,
487 };
488
489 BUTTON button_call_decline = {
490 .panel = {
491 .type = PANEL_BUTTON,
492 .x = -186,
493 .y = 10,
494 .width = _BM_LBUTTON_WIDTH,
495 .height = _BM_LBUTTON_HEIGHT,
496 },
497 .bm_fill = BM_LBUTTON,
498 .bm_icon = BM_DECLINE,
499 .icon_w = _BM_LBICON_WIDTH,
500 .icon_h = _BM_LBICON_HEIGHT,
501 .on_mup = button_call_decline_on_mup,
502 .update = button_call_decline_update,
503 .tooltip_text = {.i18nal = STR_CALL_DECLINE },
504 .nodraw = true,
505 .disabled = true,
506 };
507
508 BUTTON button_call_audio = {
509 .panel = {
510 .type = PANEL_BUTTON,
511 .x = -124,
512 .y = 10,
513 .width = _BM_LBUTTON_WIDTH,
514 .height = _BM_LBUTTON_HEIGHT,
515 },
516 .bm_fill = BM_LBUTTON,
517 .bm_icon = BM_CALL,
518 .icon_w = _BM_LBICON_WIDTH,
519 .icon_h = _BM_LBICON_HEIGHT,
520 .on_mup = button_call_audio_on_mup,
521 .update = button_call_audio_update,
522 .tooltip_text = {.i18nal = STR_CALL_START_AUDIO },
523 };
524
525 BUTTON button_call_video = {
526 .panel = {
527 .type = PANEL_BUTTON,
528 .x = -62,
529 .y = 10,
530 .width = _BM_LBUTTON_WIDTH,
531 .height = _BM_LBUTTON_HEIGHT,
532 },
533 .bm_fill = BM_LBUTTON,
534 .bm_icon = BM_VIDEO,
535 .icon_w = _BM_LBICON_WIDTH,
536 .icon_h = _BM_LBICON_HEIGHT,
537 .on_mup = button_call_video_on_mup,
538 .update = button_call_video_update,
539 .tooltip_text = {.i18nal = STR_CALL_START_VIDEO },
540 };
541
button_send_file_on_mup(void)542 static void button_send_file_on_mup(void) {
543 FRIEND *f = flist_get_friend();
544 if (!f) {
545 LOG_ERR("Friend", "Could not get selected friend.");
546 return;
547 }
548
549 if (f->online) {
550 openfilesend();
551 }
552 }
553
button_send_file_update(BUTTON * b)554 static void button_send_file_update(BUTTON *b) {
555 FRIEND *f = flist_get_friend();
556 if (!f) {
557 LOG_ERR("Friend", "Could not get selected friend.");
558 return;
559 }
560
561 if (f->online) {
562 b->disabled = false;
563 button_setcolors_success(b);
564 } else {
565 b->disabled = true;
566 button_setcolors_disabled(b);
567 }
568 }
569
570 BUTTON button_send_file = {
571 .panel = {
572 .type = PANEL_BUTTON,
573 .x = 6,
574 .y = -46,
575 .width = _BM_CHAT_BUTTON_WIDTH,
576 .height = _BM_CHAT_BUTTON_HEIGHT,
577 },
578 .bm_fill = BM_CHAT_BUTTON_LEFT,
579 .bm_icon = BM_FILE,
580 .icon_w = _BM_FILE_WIDTH,
581 .icon_h = _BM_FILE_HEIGHT,
582 .on_mup = button_send_file_on_mup,
583 .update = button_send_file_update,
584 .disabled = true,
585 .tooltip_text = {.i18nal = STR_SEND_FILE },
586 };
587
588 #include "../screen_grab.h"
button_send_screenshot_on_mup(void)589 static void button_send_screenshot_on_mup(void) {
590 FRIEND *f = flist_get_friend();
591 if (f != NULL && f->online) {
592 utox_screen_grab_desktop(0);
593 }
594 }
595
button_send_screenshot_update(BUTTON * b)596 static void button_send_screenshot_update(BUTTON *b) {
597 FRIEND *f = flist_get_friend();
598 if (!f) {
599 LOG_ERR("Friend", "Could not get selected friend.");
600 return;
601 }
602
603 if (f->online) {
604 b->disabled = false;
605 button_setcolors_success(b);
606 } else {
607 b->disabled = true;
608 button_setcolors_disabled(b);
609 }
610 }
611
612 BUTTON button_send_screenshot = {
613 .panel = {
614 .type = PANEL_BUTTON,
615 .x = 8 + _BM_CHAT_BUTTON_WIDTH,
616 .y = -46,
617 .width = _BM_CHAT_BUTTON_WIDTH,
618 .height = _BM_CHAT_BUTTON_HEIGHT,
619 },
620 .bm_fill = BM_CHAT_BUTTON_RIGHT,
621 .bm_icon = BM_CHAT_BUTTON_OVERLAY_SCREENSHOT,
622 .icon_w = _BM_CHAT_BUTTON_OVERLAY_WIDTH,
623 .icon_h = _BM_CHAT_BUTTON_OVERLAY_HEIGHT,
624 .update = button_send_screenshot_update,
625 .on_mup = button_send_screenshot_on_mup,
626 .tooltip_text = {.i18nal = STR_SENDSCREENSHOT },
627 };
628
629 BUTTON button_accept_friend = {
630 .panel = {
631 .type = PANEL_BUTTON,
632 .x = -140,
633 .y = -80,
634 .width = _BM_SBUTTON_WIDTH,
635 .height = _BM_SBUTTON_HEIGHT,
636 },
637 .bm_fill = BM_SBUTTON,
638 .button_text = {.i18nal = STR_ADD },
639 .update = button_setcolors_success,
640 .on_mup = button_accept_friend_on_mup,
641 };
642
643 BUTTON button_ignore_friend = {
644 .panel = {
645 .type = PANEL_BUTTON,
646 .x = -80,
647 .y = -80,
648 .width = _BM_SBUTTON_WIDTH,
649 .height = _BM_SBUTTON_HEIGHT,
650 },
651 .bm_fill = BM_SBUTTON,
652 .button_text = {.i18nal = STR_IGNORE},
653 .update = button_setcolors_danger,
654 .on_mup = button_ignore_friend_on_mup,
655 };
656
switchfxn_autoaccept_ft(void)657 static void switchfxn_autoaccept_ft(void) {
658 FRIEND *f = flist_get_friend();
659 if (f) {
660 f->ft_autoaccept = !f->ft_autoaccept;
661 utox_write_metadata(f);
662 }
663 }
664
665 #include "../ui/switch.h"
666
667 UISWITCH switch_friend_autoaccept_ft = {
668 .panel = {
669 .type = PANEL_SWITCH,
670 .x = 10,
671 .y = 168,
672 .width = _BM_SWITCH_WIDTH,
673 .height = _BM_SWITCH_HEIGHT,
674 },
675 .style_outer = BM_SWITCH,
676 .style_toggle = BM_SWITCH_TOGGLE,
677 .style_icon_off = BM_NO,
678 .style_icon_on = BM_YES,
679 .update = switch_update,
680 .on_mup = switchfxn_autoaccept_ft,
681 .tooltip_text = {.i18nal = STR_FRIEND_AUTOACCEPT },
682 };
683
684
edit_add_new_contact(EDIT * UNUSED (edit))685 static void edit_add_new_contact(EDIT *UNUSED(edit)) {
686 friend_add(edit_add_new_friend_id.data, edit_add_new_friend_id.length, edit_add_new_friend_msg.data, edit_add_new_friend_msg.length);
687 }
688
689 static char e_friend_pubkey_str[TOX_PUBLIC_KEY_SIZE * 2];
690 EDIT edit_friend_pubkey = {
691 .panel = {
692 .type = PANEL_EDIT,
693 .x = 10,
694 .y = 88,
695 .width = -10,
696 .height = 24,
697 },
698 // .length == .data_size, because .data is not \0-terminated
699 .length = sizeof e_friend_pubkey_str,
700 .data_size = sizeof e_friend_pubkey_str,
701 .data = e_friend_pubkey_str,
702 .readonly = true,
703 .noborder = false,
704 .select_completely = true,
705 };
706
707
edit_friend_alias_onenter(EDIT * UNUSED (edit))708 static void edit_friend_alias_onenter(EDIT *UNUSED(edit)) {
709 FRIEND *f = flist_get_friend();
710 if (!f) {
711 LOG_ERR("Friend", "Could not get selected friend.");
712 return;
713 }
714
715 friend_set_alias(f, (uint8_t *)edit_friend_alias.data, edit_friend_alias.length);
716
717 utox_write_metadata(f);
718 }
719
720 static char e_friend_alias_str[128];
721 EDIT edit_friend_alias = {
722 .panel = {
723 .type = PANEL_EDIT,
724 .x = 10,
725 .y = 138,
726 .width = -10,
727 .height = 24,
728 },
729 .data_size = sizeof e_friend_alias_str,
730 .data = e_friend_alias_str,
731 .onenter = edit_friend_alias_onenter,
732 .onlosefocus = edit_friend_alias_onenter,
733 .empty_str = {.plain = STRING_INIT("") }, // set dynamically to the friend's name
734 };
735
736
737
edit_add_new_friend_id_ontab(EDIT * UNUSED (edit))738 static void edit_add_new_friend_id_ontab(EDIT *UNUSED(edit)) {
739 edit_setfocus(&edit_add_new_friend_msg);
740 }
741
742 static char e_add_new_friend_id_data[TOX_ADDRESS_SIZE * 4];
743 EDIT edit_add_new_friend_id = {
744 .panel = {
745 .type = PANEL_EDIT,
746 .x = 10,
747 .y = 28 + MAIN_TOP,
748 .width = -10,
749 .height = 24,
750 },
751 .data_size = sizeof e_add_new_friend_id_data,
752 .data = e_add_new_friend_id_data,
753 .onenter = edit_add_new_contact,
754 .ontab = edit_add_new_friend_id_ontab,
755 .onshifttab = edit_add_new_friend_id_ontab,
756 };
757
758 SCROLLABLE e_add_new_friend_msg_scroll = {
759 .panel = { .type = PANEL_SCROLLABLE, },
760 .d = 1.0,
761 .color = C_SCROLL,
762 };
763
edit_add_new_friend_msg_ontab(EDIT * UNUSED (edit))764 static void edit_add_new_friend_msg_ontab(EDIT *UNUSED(edit)) {
765 edit_setfocus(&edit_add_new_friend_id);
766 }
767
768 static char e_add_new_friend_msg_data[1024];
769 EDIT edit_add_new_friend_msg = {
770 .panel = {
771 .type = PANEL_EDIT,
772 .x = 10,
773 .y = 76 + MAIN_TOP,
774 .width = -10,
775 .height = 84,
776 },
777 .multiline = 1,
778 .scroll = &e_add_new_friend_msg_scroll,
779 .data = e_add_new_friend_msg_data,
780 .data_size = sizeof e_add_new_friend_msg_data,
781 .empty_str = {.i18nal = STR_DEFAULT_FRIEND_REQUEST_MESSAGE },
782 .ontab = edit_add_new_friend_msg_ontab,
783 .onshifttab = edit_add_new_friend_msg_ontab,
784 };
785
786 #include "../commands.h"
e_chat_msg_onenter(EDIT * edit)787 static void e_chat_msg_onenter(EDIT *edit) {
788 char * text = edit->data;
789 uint16_t length = edit->length;
790
791 if (length <= 0) {
792 return;
793 }
794
795 uint16_t command_length = 0; //, argument_length = 0;
796 char * command = NULL, *argument = NULL;
797
798 command_length = utox_run_command(text, length, &command, &argument, 1);
799
800 // TODO: Magic number
801 if (command_length == UINT16_MAX) {
802 edit->length = 0;
803 return;
804 }
805
806 // LOG_TRACE("Layout Friend", "cmd %u", command_length);
807
808 bool action = false;
809 if (command_length) {
810 length = length - command_length - 2; /* first / and then the SPACE */
811 text = argument;
812 if ((command_length == 2) && (!memcmp(command, "me", 2))) {
813 if (argument) {
814 action = true;
815 } else {
816 return;
817 }
818 }
819 }
820
821 if (!text) {
822 return;
823 }
824
825 FRIEND *f = flist_get_friend();
826 if (f) {
827 /* Display locally */
828 if (action) {
829 message_add_type_action(&f->msg, 1, text, length, 1, 1);
830 } else {
831 message_add_type_text(&f->msg, 1, text, length, 1, 1);
832 }
833 }
834 edit->length = 0;
835 }
836
e_chat_msg_onchange(EDIT * UNUSED (edit))837 static void e_chat_msg_onchange(EDIT *UNUSED(edit)) {
838 FRIEND *f = flist_get_friend();
839 if (f) {
840 if (!f->online) {
841 return;
842 }
843
844 postmessage_toxcore(TOX_SEND_TYPING, f->number, 0, NULL);
845 }
846 }
847
848 SCROLLABLE e_chat_msg_friend_scroll = {
849 .panel = { .type = PANEL_SCROLLABLE, },
850 .d = 1.0,
851 .color = C_SCROLL,
852 };
853
854 static char e_chat_msg_friend_data[65535];
855 EDIT edit_chat_msg_friend = {
856 .panel = {
857 .type = PANEL_EDIT,
858 .x = 10 + _BM_CHAT_BUTTON_WIDTH * 2, /* Make space for the left button */
859 .y = -46,
860 .width = -64,
861 .height = 40, /* text is 8 high. 8 * 2.5 = 20. */
862 },
863 .data = e_chat_msg_friend_data,
864 .data_size = sizeof e_chat_msg_friend_data,
865 .multiline = true,
866 .onenter = e_chat_msg_onenter,
867 .onchange = e_chat_msg_onchange,
868 .scroll = &e_chat_msg_friend_scroll,
869 };
870
871 /* Button to send chat message */
button_chat_send_friend_on_mup(void)872 static void button_chat_send_friend_on_mup(void) {
873 // TODO clear the chat bar with a /slash command
874 e_chat_msg_onenter(&edit_chat_msg_friend);
875 // reset focus to the chat window on send to prevent segfault. May break on android.
876 edit_setfocus(&edit_chat_msg_friend);
877 }
878
button_chat_send_friend_update(BUTTON * b)879 static void button_chat_send_friend_update(BUTTON *b) {
880 FRIEND *f = flist_get_friend();
881 if (f) {
882 if (f->online) {
883 button_setcolors_success(b);
884 } else {
885 button_setcolors_disabled(b);
886 }
887 }
888 }
889
890 BUTTON button_chat_send_friend = {
891 .panel = {
892 .type = PANEL_BUTTON,
893 .x = -6 - _BM_CHAT_SEND_WIDTH,
894 .y = -46,
895 .width = _BM_CHAT_SEND_WIDTH,
896 .height = _BM_CHAT_SEND_HEIGHT,
897 },
898 .bm_fill = BM_CHAT_SEND,
899 .bm_icon = BM_CHAT_SEND_OVERLAY,
900 .icon_w = _BM_CHAT_SEND_OVERLAY_WIDTH,
901 .icon_h = _BM_CHAT_SEND_OVERLAY_HEIGHT,
902 .on_mup = button_chat_send_friend_on_mup,
903 .update = button_chat_send_friend_update,
904 .tooltip_text = {.i18nal = STR_SENDMESSAGE },
905 };
906
button_confirm_deletion_on_mup(void)907 static void button_confirm_deletion_on_mup(void) {
908 flist_delete_rmouse_item();
909 }
910
button_deny_deletion_on_mup(void)911 static void button_deny_deletion_on_mup(void) {
912 panel_friend_confirm_deletion.disabled = true;
913 panel_friend_chat.disabled = false;
914 }
915
916 BUTTON button_confirm_deletion = {
917 .panel = {
918 .type = PANEL_BUTTON,
919 .x = 10,
920 .y = MAIN_TOP + 40,
921 .width = _BM_SBUTTON_WIDTH,
922 .height = _BM_SBUTTON_HEIGHT,
923 },
924 .bm_fill = BM_SBUTTON,
925 .update = button_setcolors_danger,
926 .tooltip_text = {.i18nal = STR_DELETE},
927 .button_text = {.i18nal = STR_DELETE},
928 .on_mup = button_confirm_deletion_on_mup,
929 };
930
931 BUTTON button_deny_deletion = {
932 .panel = {
933 .type = PANEL_BUTTON,
934 .x = 110,
935 .y = MAIN_TOP + 40,
936 .width = _BM_SBUTTON_WIDTH,
937 .height = _BM_SBUTTON_HEIGHT,
938 },
939 .bm_fill = BM_SBUTTON,
940 .update = button_setcolors_success,
941 .tooltip_text = {.i18nal = STR_KEEP},
942 .button_text = {.i18nal = STR_KEEP},
943 .on_mup = button_deny_deletion_on_mup,
944 };
945