diff options
Diffstat (limited to 'src/fruits/cmc')
| -rw-r--r-- | src/fruits/cmc/cmc.c | 128 | ||||
| -rw-r--r-- | src/fruits/cmc/cmc.h | 27 | ||||
| -rw-r--r-- | src/fruits/cmc/cmc.py | 17 | ||||
| -rw-r--r-- | src/fruits/cmc/meson.build | 15 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/pager.c | 88 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/pager.h | 33 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/pane_lists.c | 93 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/pane_lists.h | 20 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/pane_search.c | 335 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/pane_search.h | 29 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/resources.c | 85 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/resources.h | 31 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/ui.c | 144 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/ui.h | 40 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/view.h | 24 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/view_twitter.c | 370 | ||||
| -rw-r--r-- | src/fruits/cmc/tui/view_twitter.h | 35 |
17 files changed, 17 insertions, 1497 deletions
diff --git a/src/fruits/cmc/cmc.c b/src/fruits/cmc/cmc.c deleted file mode 100644 index 5bbdb0b..0000000 --- a/src/fruits/cmc/cmc.c +++ /dev/null @@ -1,128 +0,0 @@ -#include <al/lib.h> -#include <al/log.h> -#include <al/wstr.h> -#include <al/random.h> -#include <aki/common.h> -#include <aki/event_loop.h> - -#include "../../server/common.h" - -#include "cmc.h" - -static void client_callback(void *userdata, u8 op, void *opaque) -{ - struct cmc *c = (struct cmc *)userdata; - switch (op) { - case CAMU_CLIENT_STATE_UPDATED: { - switch (c->action) { - case CMC_ACTION_OPEN: { - cmc_ui_open(&c->ui, c); - break; - } - case CMC_ACTION_LIST: { - switch (c->type) { - case CMC_LIST: { - struct camu_list *list; - al_array_foreach(c->client.state.lists, i, list) { - al_printf("%.*s:\n", AL_STR_PRINTF(&list->name)); - str *unique_id; - al_array_foreach_ptr(list->entries, j, unique_id) { - if ((s32)j == list->current) { - al_printf(" > %.*s\n", AL_STR_PRINTF(unique_id)); - } else { - al_printf(" %.*s\n", AL_STR_PRINTF(unique_id)); - } - } - } - aki_event_loop_break(&c->loop); - break; - } - case CMC_SEARCH: { - struct camu_search *search; - al_array_foreach(c->client.state.searches, i, search) { - al_printf("%u %x %.*s\n", i, search->id, AL_STR_PRINTF(&search->query)); - } - aki_event_loop_break(&c->loop); - break; - } - } - break; - } - } - break; - } - case CAMU_CLIENT_SEARCH_CREATED: { - aki_event_loop_break(&c->loop); - break; - } - case CAMU_CLIENT_RESULTS: { - cmc_ui_handle_results(&c->ui.search, (struct camu_result_list *)opaque); - break; - } - case CAMU_CLIENT_END_OF_RESULTS: { - cmc_ui_handle_end_of_results(&c->ui.search, *((s32 *)opaque)); - break; - } - case CAMU_CLIENT_DISCONNECTED: - aki_event_loop_break(&c->loop); - break; - } -} - -static struct cmc c = { 0 }; - -s32 main(s32 argc, char *argv[]) -{ - if (argc < 2 || !aki_common_init()) return EXIT_FAILURE; - - str module; - str query; - - str *cmd = al_str_cr(argv[1]); - if (al_str_eq(cmd, al_str_c("search"))) { - c.type = CMC_SEARCH; - if (argc == 2) { - c.action = CMC_ACTION_LIST; - } else { - c.action = CMC_ACTION_CREATE; - al_str_from(&module, "twitter"); - al_str_from(&query, argv[2]); - } - } else if (al_str_eq(cmd, al_str_c("open"))) { - c.action = CMC_ACTION_OPEN; - } else if (al_str_eq(cmd, al_str_c("list"))) { - c.type = CMC_LIST; - if (argc == 2) { - c.action = CMC_ACTION_LIST; - } else { - c.action = CMC_ACTION_CREATE; - } - } else { - return EXIT_FAILURE; - } - - aki_event_loop_init(&c.loop); - - camu_client_init(&c.client, &c.loop, client_callback, &c); - if (!camu_client_login(&c.client, al_str_c("andrew"), CAMU_SERVER_IP, CAMU_PORT)) { - goto err; - } - - if (c.action == CMC_ACTION_CREATE) { - if (c.type == CMC_SEARCH) { - camu_client_create_search(&c.client, &module, &query); - } - } - - aki_event_loop_run(&c.loop); - - if (c.action == CMC_ACTION_OPEN && c.ui.nc) notcurses_stop(c.ui.nc); - - camu_client_close(&c.client); - - aki_common_close(); - - return EXIT_SUCCESS; -err: - return EXIT_FAILURE; -} diff --git a/src/fruits/cmc/cmc.h b/src/fruits/cmc/cmc.h deleted file mode 100644 index 625d256..0000000 --- a/src/fruits/cmc/cmc.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include <al/types.h> -#include <aki/event_loop.h> - -#include "../../libclient/client.h" - -#include "tui/ui.h" - -enum { - CMC_LIST = 0, - CMC_SEARCH -}; - -enum { - CMC_ACTION_OPEN = 0, - CMC_ACTION_LIST, - CMC_ACTION_CREATE, -}; - -struct cmc { - u8 type; - u8 action; - struct aki_event_loop loop; - struct camu_client client; - struct cmc_ui ui; -}; diff --git a/src/fruits/cmc/cmc.py b/src/fruits/cmc/cmc.py new file mode 100644 index 0000000..5c0a5b6 --- /dev/null +++ b/src/fruits/cmc/cmc.py @@ -0,0 +1,17 @@ +import cffi +import locale +from notcurses import notcurses + +ffi = cffi.FFI() + +print(ffi.string(notcurses.lib.notcurses_version())) + +class CMC: + def __init__(self): + pass + +c = CMC() + +locale.setlocale(locale.LC_ALL, "") +nc = notcurses.Notcurses() +nc.render() diff --git a/src/fruits/cmc/meson.build b/src/fruits/cmc/meson.build deleted file mode 100644 index 57ded9c..0000000 --- a/src/fruits/cmc/meson.build +++ /dev/null @@ -1,15 +0,0 @@ -cmc_src = [ - 'cmc.c', - 'tui/ui.c', - 'tui/resources.c', - 'tui/pager.c', - 'tui/view_twitter.c', - 'tui/pane_lists.c', - 'tui/pane_search.c' -] -cmc_deps = [common_deps, libclient, subproject('stb').get_variable('stb')] - -notcurses = dependency('notcurses') -cmc_deps += [notcurses] - -executable('cmc', cmc_src, dependencies: cmc_deps) diff --git a/src/fruits/cmc/tui/pager.c b/src/fruits/cmc/tui/pager.c deleted file mode 100644 index a672315..0000000 --- a/src/fruits/cmc/tui/pager.c +++ /dev/null @@ -1,88 +0,0 @@ -#include "pager.h" - -void cmc_pager_init(struct cmc_pager *pager, u32 page) -{ - pager->find_anchor = PAGE_NONE; - pager->anchor = 0; - pager->redraw = true; - pager->selected = 0; - al_array_init(pager->prev); - pager->max_page_num = page; - pager->min_page_num = page; - pager->end_of_page = -1; - pager->pending_requests = 0; - al_array_init(pager->pages); -} - -static bool any_pending_requests(struct cmc_view_page *page) -{ - struct cmc_view *view; - al_array_foreach(page->views, j, view) { - if (view->pending_requests > 0) { - return true; - } - } - return false; -} - -bool cmc_pager_maybe_process_pages(struct cmc_pager *pager, void (*func)(void *, struct cmc_view_page *), void *userdata) -{ - bool any_page_processed = false; - struct cmc_view_page *page; - al_array_foreach(pager->pages, i, page) { - if (page->processed) continue; - if (!any_pending_requests(page)) { - page->processed = true; - func(userdata, page); - any_page_processed = true; - } - } - return any_page_processed; -} - -struct cmc_view_page *cmc_get_page_from_num(struct cmc_pager *pager, u32 num) -{ - struct cmc_view_page *page; - al_array_foreach(pager->pages, i, page) { - if (page->num == num) return page; - } - return NULL; -} - -struct cmc_view_page *cmc_pager_page_containing_index(struct cmc_pager *pager, u32 index, u32 *offset) -{ - u32 count = 0, size = 0; - struct cmc_view_page *page = NULL; - for (u32 i = pager->min_page_num; i <= pager->max_page_num; i++) { - if (!(page = cmc_get_page_from_num(pager, i))) continue; - size = page->views.size; - count += size; - if (count > index) { - if (offset) *offset = size - (count - index); - return page; - } - } - return NULL; -} - -bool cmc_pager_iterate_to_height(struct cmc_pager *pager, u32 height, u32 anchor, u32 *count, - void (*func)(void *, struct cmc_view *, u32), void *userdata) -{ - u32 y = 0, offset; - struct cmc_view_page *page = cmc_pager_page_containing_index(pager, anchor, &offset); - if (!page) return false; - struct cmc_view *view; - do { - // If the page is not processed, return out of space as to not display a discontinuity. - if (!page->processed) return true; - for (; offset < page->views.size; offset++) { - view = al_array_at(page->views, offset); - // If this post would draw past the height, return out of space. - if (y + view->rows > height) return true; - if (func) func(userdata, view, y); - (*count)++; - y += view->rows + 1; - } - } while ((offset = 0, (page = cmc_get_page_from_num(pager, page->num + 1)))); - return false; -} diff --git a/src/fruits/cmc/tui/pager.h b/src/fruits/cmc/tui/pager.h deleted file mode 100644 index 6aeeb9c..0000000 --- a/src/fruits/cmc/tui/pager.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include <al/types.h> -#include <al/array.h> - -#include "view.h" - -enum { - PAGE_NONE = 0, - PAGE_UP, - PAGE_DOWN -}; - -struct cmc_pager { - u8 find_anchor; - s32 anchor; - bool redraw; - u32 count; - s32 selected; - array(struct cmc_view *) prev; - u32 max_page_num; - u32 min_page_num; - s32 end_of_page; - u32 pending_requests; - array(struct cmc_view_page *) pages; -}; - -void cmc_pager_init(struct cmc_pager *pager, u32 page); -bool cmc_pager_maybe_process_pages(struct cmc_pager *pager, void (*func)(void *, struct cmc_view_page *), void *userdata); -struct cmc_view_page *cmc_get_page_from_num(struct cmc_pager *pager, u32 num); -struct cmc_view_page *cmc_pager_page_containing_index(struct cmc_pager *pager, u32 index, u32 *offset); -bool cmc_pager_iterate_to_height(struct cmc_pager *pager, u32 height, u32 anchor, u32 *count, - void (*func)(void *, struct cmc_view *, u32), void *userdata); diff --git a/src/fruits/cmc/tui/pane_lists.c b/src/fruits/cmc/tui/pane_lists.c deleted file mode 100644 index 6367e57..0000000 --- a/src/fruits/cmc/tui/pane_lists.c +++ /dev/null @@ -1,93 +0,0 @@ -#include "../cmc.h" - -#include "pane_lists.h" -#include "ui.h" - -void cmc_pane_lists_init(struct cmc_pane_lists *pane, struct cmc_ui *ui) -{ - pane->offset = 0; - pane->selected = 0; - pane->list = al_array_at(ui->c->client.state.lists, 0); - pane->ui = ui; -} - -bool cmc_pane_lists_handle_input(struct cmc_pane_lists *pane, struct ncinput *input) -{ - if (!(input->evtype == NCTYPE_PRESS || input->evtype == NCTYPE_UNKNOWN)) return false; - s32 rows = pane->ui->rows - 1; - s32 size = (s32)pane->list->entries.size; - if (input->id == 'j') { - if (pane->selected + 1 < size) { - pane->selected++; - if (pane->selected - pane->offset >= rows) { - pane->offset += rows; - } - return true; - } - } else if (input->id == 'k') { - if (pane->selected - 1 >= 0) { - pane->selected--; - if (pane->selected - pane->offset < 0) { - pane->offset -= rows; - } - return true; - } - } else if (input->id == 'n') { - if (pane->offset + rows < size) { - pane->offset += rows; - pane->selected += rows; - if (pane->selected >= size) { - pane->selected = size - 1; - } - return true; - } - } else if (input->id == 'p') { - if (pane->offset - rows >= 0) { - pane->offset -= rows; - pane->selected -= rows; - return true; - } - } else if (input->id == NCKEY_RETURN) { - camu_client_skipto(&pane->ui->c->client, pane->selected); - } - return false; -} - -bool cmc_pane_lists_handle_input_overlay(struct cmc_pane_lists *pane, struct ncinput *input) -{ - (void)pane; - (void)input; - return false; -} - -void cmc_pane_lists_draw_overlay(struct cmc_pane_lists *pane) -{ - (void)pane; -} - -void cmc_pane_lists_refresh(struct cmc_pane_lists *pane) -{ - struct cmc_ui *ui = pane->ui; - - ncplane_cursor_move_yx(ui->p, 0, 0); - ncplane_erase(ui->p); - notcurses_refresh(ui->nc, NULL, NULL); - notcurses_render(ui->nc); - - str *unique_id; - u32 rows = AL_MIN(pane->list->entries.size - pane->offset, ui->rows - 1); - for (u32 i = pane->offset; i < pane->offset + rows; i++) { - unique_id = &al_array_at(pane->list->entries, i); - if ((s32)i == pane->selected) { - ncplane_set_fg_palindex(ui->p, 4); - } else { - ncplane_set_fg_default(ui->p); - } - u32 cols = AL_MIN(unique_id->len, ui->cols); - for (u32 j = 0; j < cols; j++) { - ncplane_putchar_yx(ui->p, i - pane->offset, j + 1, al_str_at(unique_id, j)); - } - } - - notcurses_render(ui->nc); -} diff --git a/src/fruits/cmc/tui/pane_lists.h b/src/fruits/cmc/tui/pane_lists.h deleted file mode 100644 index 323eb52..0000000 --- a/src/fruits/cmc/tui/pane_lists.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include <al/types.h> -#include <notcurses/notcurses.h> - -#include "../../libclient/client.h" - -struct cmc_ui; -struct cmc_pane_lists { - s32 offset; - s32 selected; - struct camu_list *list; - struct cmc_ui *ui; -}; - -void cmc_pane_lists_init(struct cmc_pane_lists *pane, struct cmc_ui *ui); -bool cmc_pane_lists_handle_input(struct cmc_pane_lists *pane, struct ncinput *input); -bool cmc_pane_lists_handle_input_overlay(struct cmc_pane_lists *pane, struct ncinput *input); -void cmc_pane_lists_draw_overlay(struct cmc_pane_lists *pane); -void cmc_pane_lists_refresh(struct cmc_pane_lists *pane); diff --git a/src/fruits/cmc/tui/pane_search.c b/src/fruits/cmc/tui/pane_search.c deleted file mode 100644 index 002a4d1..0000000 --- a/src/fruits/cmc/tui/pane_search.c +++ /dev/null @@ -1,335 +0,0 @@ -#include <al/lib.h> -#include <notcurses/nckeys.h> - -#include "../cmc.h" - -#include "pane_search.h" -#include "view_twitter.h" -#include "ui.h" - -static void request_page_internal(struct cmc *c, struct cmc_search *search, u32 num) -{ - search->pager.pending_requests++; - camu_client_get_page(&c->client, search->search, num); -} - -void cmc_pane_search_init(struct cmc_pane_search *pane, struct cmc_ui *ui) -{ - pane->ui = ui; - al_array_init(pane->searches); - pane->search = NULL; - struct camu_search *s; - al_array_foreach(pane->ui->c->client.state.searches, i, s) { - struct cmc_search *search = al_alloc_object(struct cmc_search); - search->search = s; - cmc_pager_init(&search->pager, s->page); - al_array_push(pane->searches, search); - } - if (pane->searches.size > 0) { - pane->search = al_array_at(pane->searches, 0); - } -} - -static struct cmc_view *get_view_by_visual_index(struct cmc_pager *pager, s32 index) -{ - u32 offset; - struct cmc_view_page *page = cmc_pager_page_containing_index(pager, pager->anchor + index, &offset); - if (!page || !page->processed) return NULL; - return al_array_at(page->views, offset); -} - -// Given an index of a post, request the page to the offset of the page containing that post. -static bool request_page_at_page_offset(struct cmc_pane_search *pane, struct cmc_pager *pager, u32 index, s32 offset) -{ - struct cmc_view_page *page = cmc_pager_page_containing_index(pager, index, NULL); - if (page) { - s32 req = (s32)page->num + offset; - if (req < 0) return false; - request_page_internal(pane->ui->c, pane->search, req); - } - return true; -} - -static void add_selected_from_index(struct cmc *c, struct cmc_pager *pager, u32 index) -{ - struct cmc_view *view = get_view_by_visual_index(pager, pager->selected); - if (view && view->post->media.size > index) { - camu_client_add(&c->client, &view->post->unique_id, index, true); - } -} - -#define ON_LAST_PAGE(pager) \ - (pager->end_of_page >= 0 && pager->anchor + pager->count > (u32)pager->end_of_page) - -bool cmc_pane_search_handle_input(struct cmc_pane_search *pane, struct ncinput *input) -{ - struct cmc_pager *pager = &pane->search->pager; - if (!(input->evtype == NCTYPE_PRESS || input->evtype == NCTYPE_UNKNOWN)) return false; - if (input->id == 'j') { - if (pager->selected + 1 >= (s32)pager->count) { - if (pager->pending_requests > 0 || pager->find_anchor != PAGE_NONE) return false; - if (ON_LAST_PAGE(pager)) return false; - if (pager->count == 0) pager->count = 1; - u32 index = pager->anchor + pager->count; - pager->find_anchor = PAGE_DOWN; - struct cmc_view_page *page = cmc_pager_page_containing_index(pager, index, NULL); - if (!page) { - request_page_at_page_offset(pane, pager, index - 1, 1); - return false; - } - } else { - pager->selected++; - } - return true; - } else if (input->id == 'k') { - if (pager->selected - 1 < 0) { - if (pager->pending_requests > 0 || pager->find_anchor != PAGE_NONE) return false; - if (pager->anchor - 1 < 0 && !request_page_at_page_offset(pane, pager, 0, -1)) { - // The reason to do this here instead of letting it resolve in - // refresh_pane_pager() is so we can return early if - // we are at the top of the page. - return false; - } - pager->anchor--; - pager->find_anchor = PAGE_UP; - // Wait for the requested previous page to come in. - if (pager->anchor < 0) return false; - } else { - pager->selected--; - } - return true; - } else if (input->id == NCKEY_RETURN || input->id == '1') { - add_selected_from_index(pane->ui->c, pager, 0); - } else if (input->id == '2') { - add_selected_from_index(pane->ui->c, pager, 1); - } else if (input->id == '3') { - add_selected_from_index(pane->ui->c, pager, 2); - } else if (input->id == '4') { - add_selected_from_index(pane->ui->c, pager, 3); - } - return false; -} - -bool cmc_pane_search_handle_input_overlay(struct cmc_pane_search *pane, struct ncinput *input) -{ - if (!(input->evtype == NCTYPE_PRESS || input->evtype == NCTYPE_UNKNOWN)) return false; - struct cmc_ui *ui = pane->ui; - struct cmc_pager *pager = &pane->search->pager; - if (input->id == NCKEY_TAB) { - pager->redraw = true; - } else if (input->id == 'j') { - if (ui->overlay.selected + 1 < (s32)pane->searches.size) { - ui->overlay.selected++; - return true; - } - } else if (input->id == 'k') { - if (ui->overlay.selected - 1 >= 0) { - ui->overlay.selected--; - return true; - } - } else if (input->id == NCKEY_RETURN) { - cmc_ui_toggle_overlay(ui); - struct cmc_view *view; - al_array_foreach(pager->prev, j, view) { - ncplane_erase(view->container); - ncplane_reparent_family(view->container, view->container); - } - pager->prev.size = 0; - pane->search = al_array_at(pane->searches, ui->overlay.selected); - pager = &pane->search->pager; - pager->redraw = true; - return true; - } - return false; -} - -void cmc_pane_search_maybe_draw_overlay(struct cmc_pane_search *pane) -{ - struct cmc_ui *ui = pane->ui; - - if (!ui->overlay.active) return; - - ncplane_cursor_move_yx(ui->overlay.p, 0, 0); - ncplane_erase(ui->overlay.p); - - u64 color = 0; - u32 background = 0; - ncchannel_set_rgb8(&background, 255, 255, 255); - ncchannel_set_alpha(&background, 255); - ncchannels_set_fchannel(&color, background); - - ncchannel_set_rgb8(&background, 124, 12, 53); - ncchannels_set_bchannel(&color, background); - ncchannels_set_fchannel(&color, background); - ncplane_gradient(ui->overlay.p, 0, 0, ui->overlay.rows, ui->overlay.cols, "", 0, color, color, color, color); - - ncplane_set_bg_rgb8(ui->overlay.p, 124, 12, 53); - - struct cmc_search *search; - al_array_foreach(ui->search.searches, i, search) { - if ((s32)i == ui->overlay.selected) { - ncplane_set_fg_palindex(ui->overlay.p, 4); - } else { - ncplane_set_fg_default(ui->overlay.p); - } - str *query = &search->search->query; - for (u32 j = 0; j < query->len; j++) { - ncplane_putchar_yx(ui->overlay.p, i, j + 1, al_str_at(query, j)); - } - } -} - -static void draw_selection_line(struct cmc_view *view, u32 y, u32 rows) -{ - ncplane_move_yx(view->container, y, 0); - wchar_t box = L'█'; - u32 k = ((struct cmc_view_twitter *)view)->repost ? 1 : 0; - for (; k < rows - 1; k++) { - ncplane_cursor_move_yx(view->container, k, 0); - ncplane_putwc(view->container, box); - } -} - -void cmc_pane_search_refresh(struct cmc_pane_search *pane) -{ - struct cmc_pager *pager = &pane->search->pager; - if (pager->pending_requests > 0) return; - - u32 page = pane->search->search->page; - if (!cmc_get_page_from_num(pager, page)) { - request_page_internal(pane->ui->c, pane->search, page); - return; - } - - if (pager->find_anchor == PAGE_UP) { - u32 count; - // If find_anchor = PAGE_UP, search->anchor is index of the requested view. - s32 anchor = pager->anchor; - while (anchor >= 0) { - count = 0; - cmc_pager_iterate_to_height(pager, pane->ui->rows, anchor, &count, NULL, NULL); - // TODO: Handle count == 0. - // Is the requested view still visible? - if ((s32)(anchor + count) - 1 < pager->anchor) break; - anchor--; - // Load more posts if needed. - if (anchor < 0 && request_page_at_page_offset(pane, pager, 0, -1)) return; - } - anchor++; // We want the anchor before the last attempt above. - pager->selected = abs(pager->anchor - anchor); - pager->anchor = anchor; - pager->redraw = true; - pager->find_anchor = PAGE_NONE; - } else if (pager->find_anchor == PAGE_DOWN) { - // When moving down we already know how many views are being displayed - // so just move the anchor 1 past that. - pager->selected = 0; - pager->anchor += pager->count; - pager->redraw = true; - pager->find_anchor = PAGE_NONE; - } - - cmc_pane_search_maybe_draw_overlay(pane); - - struct cmc_view *view; - bool out_of_space = true; - if (pager->redraw) { - al_array_foreach(pager->prev, j, view) { - ncplane_erase(view->container); - ncplane_reparent_family(view->container, view->container); - } - pager->prev.size = 0; - pager->count = 0; - out_of_space = cmc_pager_iterate_to_height(pager, pane->ui->rows, pager->anchor, &pager->count, cmc_draw_tweet_func, pane->ui); - } else { - al_array_foreach(pager->prev, j, view) { - ncplane_erase(view->container); - } - } - if ((view = get_view_by_visual_index(pager, pager->selected))) { - draw_selection_line(view, view->y, view->rows); - } - if (pager->redraw) { - pager->redraw = false; - notcurses_refresh(pane->ui->nc, NULL, NULL); - } - notcurses_render(pane->ui->nc); - if (pager->count > 0 && !out_of_space && pager->end_of_page == -1) { - request_page_at_page_offset(pane, pager, (pager->anchor + pager->count) - 1, 1); - } -} - -static struct cmc_search *get_search_from_id(struct cmc_pane_search *pane, s32 id) -{ - struct cmc_search *search; - al_array_foreach(pane->searches, i, search) { - if (search->search->id == id) return search; - } - return NULL; -} - -static void process_page_func(void *userdata, struct cmc_view_page *page) -{ - struct cmc_ui *ui = (struct cmc_ui *)userdata; - struct cmc_view *view; - al_array_foreach(page->views, i, view) { - view->rows = cmc_layout_tweet(ui, (struct cmc_view_twitter *)view, ui->cols); - cmc_draw_tweet((struct cmc_view_twitter *)view, view->container, view->rows, ui->cols); - } -} - -void cmc_ui_resources_callback(void *userdata) -{ - struct cmc_pane_search *pane = (struct cmc_pane_search *)userdata; - struct cmc_pager *pager = &pane->search->pager; - if (cmc_pager_maybe_process_pages(pager, process_page_func, pane->ui)) { - pager->redraw = true; - cmc_pane_search_refresh(pane); - } -} - -void cmc_ui_handle_results(struct cmc_pane_search *pane, struct camu_result_list *results) -{ - struct cmc_search *search = get_search_from_id(pane, results->search->id); - if (!search) return; - struct cmc_pager *pager = &search->pager; - pager->pending_requests--; - - struct cmc_view_page *page = al_alloc_object(struct cmc_view_page); - al_array_push(pager->pages, page); - page->num = results->num; - page->processed = false; - if (page->num > pager->max_page_num) pager->max_page_num = page->num; - if (page->num < pager->min_page_num) pager->min_page_num = page->num; - if (pager->find_anchor == PAGE_UP) { - pager->anchor += results->unique_ids.size; - if (pager->end_of_page >= 0) { - pager->end_of_page += results->unique_ids.size; - } - } - - str *unique_id; - struct cmc_view_twitter *view; - al_array_foreach_ptr(results->unique_ids, i, unique_id) { - view = cmc_create_view_twitter(pane->ui, unique_id); - al_array_push(page->views, &view->v); - } - - if (cmc_pager_maybe_process_pages(pager, process_page_func, pane->ui)) { - pager->redraw = true; - cmc_pane_search_refresh(pane); - } -} - -void cmc_ui_handle_end_of_results(struct cmc_pane_search *pane, s32 id) -{ - struct cmc_search *search = get_search_from_id(pane, id); - if (!search) return; - struct cmc_pager *pager = &search->pager; - pager->pending_requests--; - pager->end_of_page = (pager->anchor + pager->count) - 1; - if (cmc_pager_maybe_process_pages(pager, process_page_func, pane->ui)) { - pager->redraw = true; - cmc_pane_search_refresh(pane); - } -} diff --git a/src/fruits/cmc/tui/pane_search.h b/src/fruits/cmc/tui/pane_search.h deleted file mode 100644 index b7c5e2c..0000000 --- a/src/fruits/cmc/tui/pane_search.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include <notcurses/notcurses.h> - -#include "../../libclient/client.h" - -#include "pager.h" - -struct cmc_search { - struct camu_search *search; - struct cmc_pager pager; -}; - -struct cmc_ui; -struct cmc_pane_search { - array(struct cmc_search *) searches; - struct cmc_search *search; - struct cmc_ui *ui; -}; - -void cmc_pane_search_init(struct cmc_pane_search *pane, struct cmc_ui *ui); -bool cmc_pane_search_handle_input(struct cmc_pane_search *pane, struct ncinput *input); -bool cmc_pane_search_handle_input_overlay(struct cmc_pane_search *pane, struct ncinput *input); -void cmc_pane_search_draw_overlay(struct cmc_pane_search *pane); -void cmc_pane_search_refresh(struct cmc_pane_search *pane); - -void cmc_ui_resources_callback(void *userdata); -void cmc_ui_handle_results(struct cmc_pane_search *pane, struct camu_result_list *results); -void cmc_ui_handle_end_of_results(struct cmc_pane_search *pane, s32 id); diff --git a/src/fruits/cmc/tui/resources.c b/src/fruits/cmc/tui/resources.c deleted file mode 100644 index 19513bf..0000000 --- a/src/fruits/cmc/tui/resources.c +++ /dev/null @@ -1,85 +0,0 @@ -#include <al/log.h> -#include <al/random.h> -#define STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_STATIC -#define STBI_NO_STDIO -#define STBI_NO_FAILURE_STRINGS -#define STBI_MALLOC al_malloc -#define STBI_FREE al_free -#define STBI_REALLOC al_realloc -#include <stb_image.h> - -#include "resources.h" -#include "view.h" - -static void resource_client_callback(void *userdata, u16 id, struct aki_buffer *buffer) -{ - struct cmc_resources *resources = (struct cmc_resources *)userdata; - struct cmc_view_resource *resource; - al_array_foreach(resources->cache, i, resource) { - if (resource->id == id) { - s32 w, h, channels; - u8 *pixels = stbi_load_from_memory(aki_buffer_get_ptr(buffer, 0), buffer->size, &w, &h, &channels, 0); - if (channels == 3) { - resource->v = ncvisual_from_rgb_packed(pixels, h, w * channels, w, 255); - } else if (channels == 4) { - resource->v = ncvisual_from_rgba(pixels, h, w * channels, w); - } else { - al_log_warn("cmc", "Image has unsupported channel count."); - } - stbi_image_free(pixels); - ncvisual_geom(resources->nc, resource->v, &resource->vopts, &resource->geom); - struct cmc_view *view; - al_array_foreach(resource->refs, j, view) { - view->pending_requests--; - } - al_array_free(resource->refs); - break; - } - } - resources->callback(resources->userdata); -} - -bool cmc_resources_connect(struct cmc_resources *resources, struct notcurses *nc, - struct aki_event_loop *loop, str *addr, s32 port) -{ - resources->nc = nc; - resources->pending_requests = 0; - camu_resource_client_init(&resources->client, loop, resource_client_callback, resources); - return camu_resource_client_connect(&resources->client, addr, port); -} - -void cmc_resources_set_callback(struct cmc_resources *resources, void (*callback)(void *), void *userdata) -{ - resources->callback = callback; - resources->userdata = userdata; -} - -static struct cmc_view_resource *create_resource(struct cmc_resources *resources, str *unique_id, u32 index) -{ - struct cmc_view_resource *resource = al_alloc_object(struct cmc_view_resource); - al_array_push(resources->cache, resource); - resource->vopts.blitter = NCBLIT_PIXEL; - resource->vopts.scaling = NCSCALE_SCALE; - resource->id = al_rand_u16(); - al_str_clone(&resource->unique_id, unique_id); - resource->index = index; - al_array_init(resource->refs); - camu_resource_request(&resources->client, unique_id, index, resource->id); - return resource; -} - -struct cmc_view_resource *cmc_get_resource_from_cache(struct cmc_resources *resources, struct cmc_view *view, - str *unique_id, u32 index) -{ - struct cmc_view_resource *resource; - al_array_foreach(resources->cache, i, resource) { - if (al_str_eq(&resource->unique_id, unique_id) && resource->index == index) { - return resource; - } - } - resource = create_resource(resources, unique_id, index); - view->pending_requests++; - al_array_push(resource->refs, view); - return resource; -} diff --git a/src/fruits/cmc/tui/resources.h b/src/fruits/cmc/tui/resources.h deleted file mode 100644 index f12d861..0000000 --- a/src/fruits/cmc/tui/resources.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include <notcurses/notcurses.h> - -#include "../../libclient/resource_client.h" - -struct cmc_view; -struct cmc_view_resource { - u16 id; - str unique_id; - u32 index; - array(struct cmc_view *) refs; - struct ncvisual *v; - struct ncvgeom geom; - struct ncvisual_options vopts; -}; - -struct cmc_resources { - struct camu_resource_client client; - u32 pending_requests; - struct notcurses *nc; - array(struct cmc_view_resource *) cache; - void (*callback)(void *); - void *userdata; -}; - -bool cmc_resources_connect(struct cmc_resources *resources, struct notcurses *nc, - struct aki_event_loop *loop, str *addr, s32 port); -void cmc_resources_set_callback(struct cmc_resources *resources, void (*callback)(void *), void *userdata); -struct cmc_view_resource *cmc_get_resource_from_cache(struct cmc_resources *resources, struct cmc_view *view, - str *unique_id, u32 index); diff --git a/src/fruits/cmc/tui/ui.c b/src/fruits/cmc/tui/ui.c deleted file mode 100644 index 2c406bd..0000000 --- a/src/fruits/cmc/tui/ui.c +++ /dev/null @@ -1,144 +0,0 @@ -#include "../../server/common.h" - -#include "../cmc.h" - -#include "ui.h" - -/* -struct nccell ul, ur; nccell_init(&ul); nccell_init(&ur); -struct nccell ll, lr; nccell_init(&ll); nccell_init(&lr); -struct nccell hl, vl; nccell_init(&hl); nccell_init(&vl); -//nccell_set_channels(&hl, color); -//nccell_set_channels(&vl, color); - -ncplane_box(tui->overlay.p, &ul, &ur, &ll, &lr, &hl, &vl, tui->overlay.rows - 1, tui->overlay.cols - 1, 0); - -nccell_release(tui->overlay.p, &ul); nccell_release(tui->overlay.p, &ur); -nccell_release(tui->overlay.p, &ll); nccell_release(tui->overlay.p, &lr); -nccell_release(tui->overlay.p, &hl); nccell_release(tui->overlay.p, &vl); -*/ - -//ncplane_double_box(tui->overlay.p, NCSTYLE_NONE, color, tui->overlay.rows - 1, tui->overlay.cols - 1, 0); -//ncplane_rounded_box(tui->overlay.p, NCSTYLE_NONE, color, tui->overlay.rows - 1, tui->overlay.cols - 1, 0); - -void cmc_ui_toggle_overlay(struct cmc_ui *ui) -{ - if (ui->overlay.active) { - ncplane_reparent_family(ui->overlay.p, ui->overlay.p); - } else { - ncplane_reparent_family(ui->overlay.p, ui->p); - } - ui->overlay.active = !ui->overlay.active; -} - -static void refresh_internal(struct cmc_ui *ui) -{ - switch (ui->pane) { - case CMC_PANE_LIBRARY: - break; - case CMC_PANE_LISTS: - cmc_pane_lists_refresh(&ui->lists); - break; - case CMC_PANE_BROWSE: - break; - case CMC_PANE_SEARCH: - cmc_pane_search_refresh(&ui->search); - break; - } -} - -static void input_poll_callback(void *userdata, s32 revents) -{ - struct cmc_ui *ui = (struct cmc_ui *)userdata; - (void)revents; - struct ncinput input; - u32 ret; - bool do_refresh = false; - do { - ret = notcurses_get_nblock(ui->nc, &input); - if (ret == (u32)-1 || ret == 0) break; - if (input.evtype == NCTYPE_PRESS || input.evtype == NCTYPE_UNKNOWN) { - if (input.id == 'q') { - aki_event_loop_break(&ui->c->loop); - break; - } else if (input.id == NCKEY_TAB) { - cmc_ui_toggle_overlay(ui); - do_refresh = true; - } - switch (ui->pane) { - case CMC_PANE_LIBRARY: - break; - case CMC_PANE_LISTS: - if (ui->overlay.active) { - do_refresh |= cmc_pane_lists_handle_input_overlay(&ui->lists, &input); - } else { - do_refresh |= cmc_pane_lists_handle_input(&ui->lists, &input); - } - break; - case CMC_PANE_BROWSE: - break; - case CMC_PANE_SEARCH: - if (ui->overlay.active) { - do_refresh |= cmc_pane_search_handle_input_overlay(&ui->search, &input); - } else { - do_refresh |= cmc_pane_search_handle_input(&ui->search, &input); - } - break; - } - } - } while (1); - if (do_refresh) refresh_internal(ui); -} - -static s32 resize_cb(struct ncplane *p) -{ - struct cmc_ui *ui = (struct cmc_ui *)ncplane_userptr(p); - notcurses_stddim_yx(ui->nc, &ui->rows, &ui->cols); - ui->cols -= 4; - ui->rows -= 1; - struct ncplane_options nopts = { 0 }; - nopts.cols = ui->cols; - nopts.rows = ui->rows; - nopts.x = 3; - nopts.y = 1; - nopts.flags = 0; - ui->p = ncplane_create(p, &nopts); - ui->pane = CMC_PANE_SEARCH; - ui->overlay.cols = nopts.cols = 35; - ui->overlay.rows = nopts.rows = 20; - nopts.x = (ui->cols / 2) - (ui->overlay.cols / 2); - nopts.y = (ui->rows / 2) - (ui->overlay.rows / 2); - ui->overlay.p = ncpile_create(ui->nc, &nopts); - return 0; -} - -bool cmc_ui_open(struct cmc_ui *ui, struct cmc *c) -{ - if (!(ui->nc = notcurses_init(NULL, stdin))) return false; - - ui->c = c; - - cmc_pane_lists_init(&ui->lists, ui); - cmc_pane_search_init(&ui->search, ui); - - //if (!cmc_resources_connect(&ui->resources, ui->nc, &ui->c->loop, CAMU_SERVER_IP, CAMU_RESOURCE_PORT)) { - // return false; - //} - cmc_resources_set_callback(&ui->resources, cmc_ui_resources_callback, &ui->search); - - aki_poll_init(&ui->input, input_poll_callback, ui); - aki_poll_set(&ui->input, notcurses_inputready_fd(ui->nc), AKI_POLL_READ); - aki_poll_start(&ui->input, &c->loop); - - ui->overlay.active = false; - ui->overlay.selected = 0; - - struct ncplane *stdplane = notcurses_stdplane(ui->nc); - ncplane_set_resizecb(stdplane, resize_cb); - ncplane_set_userptr(stdplane, ui); - resize_cb(stdplane); - - refresh_internal(ui); - - return true; -} diff --git a/src/fruits/cmc/tui/ui.h b/src/fruits/cmc/tui/ui.h deleted file mode 100644 index 76ea353..0000000 --- a/src/fruits/cmc/tui/ui.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include <aki/event_loop.h> -#include <notcurses/notcurses.h> - -#include "resources.h" -#include "pane_lists.h" -#include "pane_search.h" - -enum { - CMC_PANE_LIBRARY = 0, - CMC_PANE_LISTS, - CMC_PANE_BROWSE, - CMC_PANE_SEARCH -}; - -struct cmc; -struct cmc_ui { - struct notcurses *nc; - u32 cols; - u32 rows; - struct ncplane *p; - u8 pane; - struct { - struct ncplane *p; - u32 cols; - u32 rows; - bool active; - s32 selected; - } overlay; - struct aki_poll input; - struct cmc_resources resources; - struct cmc_pane_lists lists; - struct cmc_pane_search search; - struct cmc *c; -}; - -bool cmc_ui_open(struct cmc_ui *ui, struct cmc *c); -void cmc_ui_toggle_overlay(struct cmc_ui *ui); -void cmc_ui_maybe_draw_overlay(struct cmc_ui *ui); diff --git a/src/fruits/cmc/tui/view.h b/src/fruits/cmc/tui/view.h deleted file mode 100644 index 3c521c3..0000000 --- a/src/fruits/cmc/tui/view.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <al/types.h> -#include <sho/post.h> - -enum { - CMC_VIEW_NONE = 0, - CMC_VIEW_SINGLE, - CMC_VIEW_PARTITION -}; - -struct cmc_view { - struct sho_post *post; - struct ncplane *container; - u32 pending_requests; - u32 rows; - u32 y; -}; - -struct cmc_view_page { - u32 num; - bool processed; - array(struct cmc_view *) views; -}; diff --git a/src/fruits/cmc/tui/view_twitter.c b/src/fruits/cmc/tui/view_twitter.c deleted file mode 100644 index b1070a4..0000000 --- a/src/fruits/cmc/tui/view_twitter.c +++ /dev/null @@ -1,370 +0,0 @@ -#include "../cmc.h" - -#include "view_twitter.h" - -#define TEXT_OFFSET 10 - -#define PROFILE_SIZE 5 -#define PREVIEW_OFFSET_WIDTH 26 - -static u32 count_wrapped_lines(wstr *w, u32 width) -{ - u32 counter = 0, wraps = 1; - for (u32 i = 0; i < w->len; i++) { - wchar_t wc = al_wstr_at(w, i); - s32 wcwidth = al_wchar_width(wc); - bool newline = wc == L'\n'; - if (newline || counter + wcwidth > width) { - wraps++; - counter = 0; - } - if (newline) continue; - counter += wcwidth; - } - return wraps; -} - -u32 cmc_layout_tweet(struct cmc_ui *ui, struct cmc_view_twitter *view, u32 width) -{ - struct sho_post *post = view->v.post; - struct sho_post *repost = view->repost; - - u32 rows = 1; - - view->text.width = width - TEXT_OFFSET; - view->text.height = 1 + count_wrapped_lines(&post->text, view->text.width); - view->text.y = repost ? 1 : 0; - view->text.height += view->text.y; - rows += view->text.height; - - if (view->preview.mode == CMC_VIEW_NONE) { - return rows; - } - - view->preview.width = view->text.width - 1; - view->preview.x = TEXT_OFFSET; - u32 partition_width = view->preview.width / 2; - - struct ncplane_options opts = { 0 }; - opts.cols = view->preview.width; - opts.rows = ncplane_dim_y(notcurses_stdplane(ui->nc)) / 3; - opts.x = 0; - opts.y = 0; - struct ncplane *inter = ncplane_create(notcurses_stdplane(ui->nc), &opts); - - u32 left = 0, right = 0; - struct cmc_view_resource *resource; - switch (view->preview.mode) { - case CMC_VIEW_SINGLE: { - resource = view->preview.resources[0]; - resource->vopts.n = inter; - ncvisual_geom(ui->nc, resource->v, &resource->vopts, &resource->geom); - // rcellx == width case very untested. - left += resource->geom.rcelly + (s32)((resource->geom.rcellx != view->preview.width) ? 1 : -1); - break; - } - case CMC_VIEW_PARTITION: { - ncplane_resize_simple(inter, opts.rows, partition_width); - - resource = view->preview.resources[0]; - resource->vopts.n = inter; - ncvisual_geom(ui->nc, resource->v, &resource->vopts, &resource->geom); - left += resource->geom.rcelly + 1; - - resource = view->preview.resources[1]; - resource->vopts.n = inter; - ncvisual_geom(ui->nc, resource->v, &resource->vopts, &resource->geom); - right += resource->geom.rcelly + 1; - - if (view->preview.resources[2]) { - resource = view->preview.resources[2]; - resource->vopts.n = inter; - ncvisual_geom(ui->nc, resource->v, &resource->vopts, &resource->geom); - left += resource->geom.rcelly + 1; - } - - if (view->preview.resources[3]) { - resource = view->preview.resources[3]; - resource->vopts.n = inter; - ncvisual_geom(ui->nc, resource->v, &resource->vopts, &resource->geom); - right += resource->geom.rcelly + 1; - } - - break; - } - } - - ncplane_destroy(inter); - - view->preview.height = AL_MAX(right, left); - - return rows + view->preview.height; -} - -static void date_to_relative_date(struct sho_post *post, char *out) -{ - struct sho_post_date *created = NULL; - struct sho_post_date *date; - al_array_foreach_ptr(post->dates, i, date) { - if (date->type == SHOKI_DATE_CREATED) { - created = date; - break; - } - } - if (!created) return; - f64 seconds = (aki_get_timestamp() / 1000000.0 - created->timestamp); - s64 minutes = seconds / 60L; - s64 hours = minutes / 60L; - s64 days = hours / 24L; - if (days > 0) { - al_sprintf(out, "%lud", days); - } else if (hours > 0) { - al_sprintf(out, "%luh", hours); - } else if (minutes > 0) { - al_sprintf(out, "%lum", minutes); - } else { - al_sprintf(out, "%lus", (s64)seconds); - } -} - -static void number_to_shorthand(s64 number, char *out) -{ - if (number >= 1000000000) { - al_sprintf(out, "%.1fB", number / 1000000000.f); - } else if (number >= 1000000) { - al_sprintf(out, "%.1fM", number / 1000000.f); - } else if (number >= 1000) { - al_sprintf(out, "%.1fK", number / 1000.f); - } else { - al_sprintf(out, "%ld", number); - } -} - -static void draw_tweet_resources(struct cmc_ui *ui, struct cmc_view_twitter *view) -{ - u32 partition_width = view->preview.width / 2; - struct cmc_view_resource *resource; - switch (view->preview.mode) { - case CMC_VIEW_NONE: - break; - case CMC_VIEW_SINGLE: { - resource = view->preview.resources[0]; - ncplane_resize_simple(view->preview.p[0], resource->geom.rcelly + 1, view->preview.width); - ncplane_move_yx(view->preview.p[0], view->text.height, view->preview.x); - resource->vopts.n = view->preview.p[0]; - ncvisual_blit(ui->nc, resource->v, &resource->vopts); - break; - } - case CMC_VIEW_PARTITION: { - resource = view->preview.resources[0]; - resource->vopts.n = view->preview.p[0]; - ncplane_resize_simple(view->preview.p[0], resource->geom.rcelly + 1, partition_width); - ncplane_move_yx(view->preview.p[0], view->text.height, view->preview.x); - ncvisual_blit(ui->nc, resource->v, &resource->vopts); - - resource = view->preview.resources[1]; - ncplane_resize_simple(view->preview.p[1], resource->geom.rcelly + 1, partition_width); - ncplane_move_yx(view->preview.p[1], view->text.height, (view->preview.x + view->preview.resources[0]->geom.rcellx) + 3); - resource->vopts.n = view->preview.p[1]; - ncvisual_blit(ui->nc, resource->v, &resource->vopts); - - if (view->preview.resources[2]) { - resource = view->preview.resources[2]; - ncplane_resize_simple(view->preview.p[2], resource->geom.rcelly + 1, partition_width); - ncplane_move_yx(view->preview.p[2], view->preview.resources[0]->geom.rcelly + view->text.height + 2, view->preview.x); - resource->vopts.n = view->preview.p[2]; - ncvisual_blit(ui->nc, resource->v, &resource->vopts); - } - - if (view->preview.resources[3]) { - resource = view->preview.resources[3]; - ncplane_resize_simple(view->preview.p[3], resource->geom.rcelly + 1, partition_width); - ncplane_move_yx(view->preview.p[3], view->preview.resources[1]->geom.rcelly + view->text.height + 2, (view->preview.x + view->preview.resources[2]->geom.rcellx) + 3); - resource->vopts.n = view->preview.p[3]; - ncvisual_blit(ui->nc, resource->v, &resource->vopts); - } - - break; - } - } - - if (view->profile.resource && view->profile.resource->v) { - struct cmc_view_resource *resource = view->profile.resource; - ncplane_resize_simple(view->profile.p, (PROFILE_SIZE + 1) / 2, PROFILE_SIZE); - ncplane_move_yx(view->profile.p, view->text.y, PROFILE_SIZE - 2); - resource->vopts.n = view->profile.p; - ncvisual_blit(ui->nc, resource->v, &resource->vopts); - } -} - -void cmc_draw_tweet_func(void *userdata, struct cmc_view *view, u32 y) -{ - struct cmc_ui *ui = (struct cmc_ui *)userdata; - struct cmc_search *search = ui->search.search; - ncplane_reparent_family(view->container, ui->p); - ncplane_move_yx(view->container, y, 0); - draw_tweet_resources(ui, (struct cmc_view_twitter *)view); - view->y = y; - al_array_push(search->pager.prev, view); -} - -static char format_buf[32]; - -void cmc_draw_tweet(struct cmc_view_twitter *view, struct ncplane *container, u32 rows, u32 width) -{ - struct sho_post *post = view->v.post; - struct sho_post *repost = view->repost; - - ncplane_resize_simple(container, rows, width); - - ncplane_resize_simple(view->text.p, view->text.height, width); - ncplane_move_yx(view->text.p, 0, 0); - - s32 offset = TEXT_OFFSET; - - if (repost) { - const wchar_t *retweet = L"⮤⮧"; - ncplane_set_styles(view->text.p, NCSTYLE_ITALIC); - ncplane_putwstr_yx(view->text.p, 0, offset - 3, retweet); - ncplane_set_styles(view->text.p, NCSTYLE_NONE); - ncplane_putwstr_yx(view->text.p, 0, offset, &al_wstr_at(&repost->author.display_name, 0)); - } - - ncplane_set_styles(view->text.p, NCSTYLE_BOLD); - - ncplane_putwstr_yx(view->text.p, view->text.y, offset, &al_wstr_at(&post->author.display_name, 0)); - offset += al_wstr_width(&post->author.display_name) + 1; - - ncplane_set_styles(view->text.p, NCSTYLE_NONE); - ncplane_putwstr_yx(view->text.p, view->text.y, offset, &al_wstr_at(&post->author.username, 0)); - offset += al_wstr_width(&post->author.username) + 1; - - ncplane_putwstr_yx(view->text.p, view->text.y, offset, L"∙"); - offset += 2; - - date_to_relative_date(post, format_buf); - ncplane_putstr_yx(view->text.p, view->text.y, offset, format_buf); - - u32 text_y = view->text.y + 1, text_x = TEXT_OFFSET; - for (u32 i = 0; i < post->text.len; i++) { - wchar_t wc = al_wstr_at(&post->text, i); - s32 wcwidth = al_wchar_width(wc); - bool newline = wc == L'\n'; - if (newline || text_x + wcwidth > width) { - text_y++; - text_x = TEXT_OFFSET; - } - if (newline) continue; - ncplane_putwc_yx(view->text.p, text_y, text_x, wc); - text_x += wcwidth; - } - - ncplane_resize_simple(view->stats.p, 1, view->text.width); - ncplane_move_yx(view->stats.p, rows - 1, TEXT_OFFSET); - - u32 part = 10; - offset = 0; - - if (post->comments.set) { - const wchar_t *comment = L"🗩"; - ncplane_set_styles(view->stats.p, NCSTYLE_ITALIC); - ncplane_putwstr_yx(view->stats.p, 0, offset, comment); - ncplane_set_styles(view->stats.p, NCSTYLE_NONE); - number_to_shorthand(post->comments.i, format_buf); - ncplane_putstr_yx(view->stats.p, 0, offset + 3, format_buf); - } - offset += part; - - if (post->reposts.set) { - const wchar_t *retweet = L"⮤⮧"; - ncplane_set_styles(view->stats.p, NCSTYLE_ITALIC); - ncplane_putwstr_yx(view->stats.p, 0, offset, retweet); - ncplane_set_styles(view->stats.p, NCSTYLE_NONE); - number_to_shorthand(post->reposts.i, format_buf); - ncplane_putstr_yx(view->stats.p, 0, offset + 3, format_buf); - } - offset += part; - - if (post->likes.set) { - //const wchar_t *like = L"❤"; - const wchar_t *like = L"♥"; - ncplane_set_styles(view->stats.p, NCSTYLE_ITALIC); - ncplane_putwstr_yx(view->stats.p, 0, offset, like); - ncplane_set_styles(view->stats.p, NCSTYLE_NONE); - number_to_shorthand(post->likes.i, format_buf); - ncplane_putstr_yx(view->stats.p, 0, offset + 2, format_buf); - } -} - -static void get_post_and_maybe_repost(struct cmc_ui *ui, str *unique_id, struct sho_post **post, struct sho_post **repost) -{ - struct sho_post_cache *cache = &ui->c->client.cache; - *post = sho_post_cache_get(cache, unique_id); - *repost = NULL; - if ((*post)->type == SHOKI_POST_REPOST) { - *repost = *post; - *post = sho_post_cache_get(cache, &(*post)->post.unique_id); - } -} - -static void strip_link_from_tweet(struct sho_post *post) -{ - wstr *check = al_wstr_c(L"https://t.co/"); - s32 index = al_wstr_rfind(&post->text, L':'); - if (index < 5) return; - index -= 5; // [h]ttps:// (if matched). - if (al_wstr_cmp(&post->text, check, index, check->len) == 0) { - al_wstr_at(&post->text, index) = L'\0'; - post->text.len = index; - } -} - -struct cmc_view_twitter *cmc_create_view_twitter(struct cmc_ui *ui, str *unique_id) -{ - struct cmc_view_twitter *view = al_alloc_object(struct cmc_view_twitter); - get_post_and_maybe_repost(ui, unique_id, &view->v.post, &view->repost); - - if (view->v.post->media.size > 0) { - strip_link_from_tweet(view->v.post); - } - - view->v.rows = 0; - view->v.y = 0; - view->v.pending_requests = 0; - - struct ncplane_options default_options = { 0 }; - default_options.cols = 1; - default_options.rows = 1; - default_options.x = 0; - default_options.y = 0; - - view->v.container = ncpile_create(ui->nc, &default_options); - view->text.p = ncplane_create(view->v.container, &default_options); - view->profile.p = ncplane_create(view->v.container, &default_options); - for (u32 i = 0; i < 4; i++) { - view->preview.p[i] = ncplane_create(view->v.container, &default_options); - } - view->stats.p = ncplane_create(view->v.container, &default_options); - - struct sho_post *post = view->v.post; - view->profile.resource = cmc_get_resource_from_cache(&ui->resources, &view->v, &post->author.unique_id, 0); - struct sho_post_media *media; - al_array_foreach_ptr(post->media, i, media) { - (void)media; - view->preview.resources[i] = cmc_get_resource_from_cache(&ui->resources, &view->v, &post->unique_id, i); - } - - switch (post->media.size) { - case 0: - view->preview.mode = CMC_VIEW_NONE; - break; - case 1: - view->preview.mode = CMC_VIEW_SINGLE; - break; - default: - view->preview.mode = CMC_VIEW_PARTITION; - break; - } - - return view; -} diff --git a/src/fruits/cmc/tui/view_twitter.h b/src/fruits/cmc/tui/view_twitter.h deleted file mode 100644 index 9792826..0000000 --- a/src/fruits/cmc/tui/view_twitter.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "ui.h" -#include "view.h" - -struct cmc_view_twitter { - struct cmc_view v; - struct sho_post *repost; - struct { - u32 width; - u32 height; - u32 y; - struct ncplane *p; - } text; - struct { - struct ncplane *p; - struct cmc_view_resource *resource; - } profile; - struct { - u8 mode; - u32 width; - u32 height; - u32 x; - struct ncplane *p[4]; - struct cmc_view_resource *resources[4]; - } preview; - struct { - struct ncplane *p; - } stats; -}; - -struct cmc_view_twitter *cmc_create_view_twitter(struct cmc_ui *ui, str *unique_id); -void cmc_draw_tweet(struct cmc_view_twitter *view, struct ncplane *container, u32 rows, u32 width); -u32 cmc_layout_tweet(struct cmc_ui *ui, struct cmc_view_twitter *view, u32 width); -void cmc_draw_tweet_func(void *userdata, struct cmc_view *view, u32 y); |