From 5782e69313e0c3a1980854efea46d2c487224185 Mon Sep 17 00:00:00 2001 From: PoliEcho Date: Sat, 8 Mar 2025 09:13:17 +0100 Subject: [PATCH] basic timetable ui --- src/timetable.cpp | 188 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 182 insertions(+), 6 deletions(-) diff --git a/src/timetable.cpp b/src/timetable.cpp index 95bc2c9..9040bd9 100644 --- a/src/timetable.cpp +++ b/src/timetable.cpp @@ -1,14 +1,47 @@ #include "timetable.h" +#include "color.h" +#include "helper_funcs.h" #include "net.h" #include +#include +#include #include #include #include #include #include #include +#include using nlohmann::json; +#define PADDING 10 + +#define DEFAULT_OFFSET 3 + +const wchar_t *day_abriviations[] = {nullptr, L"Mo", L"Tu", L"We", + L"Th", L"Fr", L"Sa", L"Su"}; + +void draw_grid(const uint8_t num_of_columns, const uint8_t num_of_rows, + const uint16_t cell_width, const uint16_t cell_height); + +uint8_t hour_id_to_index(uint8_t *HourIdLookupTable, uint8_t id) { + for (uint8_t i = 0; i < 10; i++) { + if (HourIdLookupTable[i] == id) { + return i; + } + } + return 0; +} + +json find_hour_by_id(const json &data, int searchId) { + for (const auto &hour : data["Hours"]) { + if (hour["Id"] == searchId) { + return hour; + } + } + + return L""; +} void timetable_page() { // DONT FORGET TO UNCOMMENT @@ -17,7 +50,65 @@ void timetable_page() { std::ifstream f("test-data/timetable.json"); json resp_from_api = json::parse(f); - // calculate table size + // this may be unnecessary but i dont have enaugh data to test it + // it sorts the hours by start time + uint8_t *HourIdLookupTable = new uint8_t[resp_from_api["Hours"].size()]; + { + using Id_and_Start_time = std::tuple; + // ID, start_time + + Id_and_Start_time *temp_hour_sorting_array = + new Id_and_Start_time[resp_from_api["Hours"].size()]; + + for (uint8_t i = 0; i < resp_from_api["Hours"].size(); i++) { + temp_hour_sorting_array[i] = std::make_tuple( + resp_from_api["Hours"][i]["Id"].get(), + resp_from_api["Hours"][i]["BeginTime"].get()); + }; + + std::sort(temp_hour_sorting_array, + temp_hour_sorting_array + resp_from_api["Hours"].size(), + [](const Id_and_Start_time &a, const Id_and_Start_time &b) { + const std::string &str_a = std::get<1>(a); + const std::string &str_b = std::get<1>(b); + + const size_t colon_pos_a = str_a.find(':'); + const size_t colon_pos_b = str_b.find(':'); + + if (colon_pos_a == std::string::npos || + colon_pos_b == std::string::npos) { + std::cerr << RED "[ERROR]" << RESET + << " Colon not found in time string\n"; + safe_exit(EXIT_FAILURE); + } + + const std::string hour_a_S = str_a.substr(0, colon_pos_a); + const std::string hour_b_S = str_b.substr(0, colon_pos_b); + + const std::string minute_a_S = str_a.substr(colon_pos_a + 1); + const std::string minute_b_S = str_b.substr(colon_pos_b + 1); + + const uint8_t hour_a = std::stoi(hour_a_S); + const uint8_t hour_b = std::stoi(hour_b_S); + + const uint8_t minute_a = std::stoi(minute_a_S); + const uint8_t minute_b = std::stoi(minute_b_S); + + return (hour_a < hour_b) || + ((hour_a == hour_b) && (minute_a < minute_b)); + }); + + for (uint8_t i = 0; i < resp_from_api["Hours"].size(); i++) { + HourIdLookupTable[i] = std::get<0>(temp_hour_sorting_array[i]); + } + + delete[] temp_hour_sorting_array; + } + + for (uint8_t i = 0; i < resp_from_api["Hours"].size(); i++) { + std::clog << (int)i << ": " << (int)HourIdLookupTable[i] << "\n"; + } + // some lambda dark magic const uint8_t num_of_columns = [&]() -> uint8_t { uint8_t result = 0; @@ -30,7 +121,7 @@ void timetable_page() { return result; }(); - const uint8_t num_of_rows = resp_from_api["Days"].size(); + const uint8_t num_of_days = resp_from_api["Days"].size(); setlocale(LC_ALL, ""); /* Initialize curses */ @@ -39,11 +130,96 @@ void timetable_page() { cbreak(); noecho(); keypad(stdscr, TRUE); + /* Initialize all the colors */ + for (uint8_t i = 0; i < 8; i++) { + init_pair(i, i, COLOR_BLACK); + } - // Use wide character printing - std::wstring msg = std::format(L"LINES: {} COLS: {}", LINES, COLS); - mvaddwstr(0, 0, msg.c_str()); + const uint16_t cell_width = (COLS - PADDING) / num_of_columns; + const uint16_t cell_height = (LINES - PADDING) / num_of_days; + + WINDOW **day_windows = new WINDOW *[num_of_days]; + WINDOW **lesson_windows = new WINDOW *[num_of_columns]; + std::vector> cells( + num_of_days, std::vector(num_of_columns)); + + for (uint8_t i = 0; i < num_of_days; i++) { + day_windows[i] = newwin(cell_height, DEFAULT_OFFSET, + i * cell_height + DEFAULT_OFFSET, 0); + // this wont draw left boarder window making it so it looks partially + // offscreen + wborder(day_windows[i], ' ', 0, 0, 0, ACS_HLINE, 0, ACS_HLINE, 0); + const wchar_t *day_abriv = + day_abriviations[resp_from_api["Days"][i]["DayOfWeek"].get()]; + + wprint_in_middle(day_windows[i], cell_height / 2, 0, wcslen(day_abriv), + day_abriv, COLOR_PAIR(0)); + wrefresh(day_windows[i]); + } + + for (uint8_t i = 0; i < num_of_columns; i++) { + + lesson_windows[i] = + newwin(DEFAULT_OFFSET, cell_width, 0, i * cell_width + DEFAULT_OFFSET); + wborder(lesson_windows[i], 0, 0, ' ', 0, ACS_VLINE, ACS_VLINE, 0, 0); + std::wstring caption; + std::wstring start_time; + std::wstring end_time; + + for (uint8_t j = 0; j < resp_from_api["Hours"].size(); j++) { + if (resp_from_api["Hours"][j]["Id"].get() == + HourIdLookupTable[i]) { + // DEBUG + // std::clog << resp_from_api["Hours"][j]["Caption"].get(); + + std::string caption_ascii = + resp_from_api["Hours"][j]["Caption"].get(); + std::string start_time_ascii = + resp_from_api["Hours"][j]["BeginTime"].get(); + std::string end_time_ascii = + resp_from_api["Hours"][j]["EndTime"].get(); + + caption = string_to_wstring(caption_ascii); + start_time = string_to_wstring(start_time_ascii); + end_time = string_to_wstring(end_time_ascii); + + goto hour_id_found; + } + } + std::cerr << RED "[ERROR]" << RESET " Hour with id " << HourIdLookupTable[i] + << " not found\n"; + goto timetable_error_exit; + + hour_id_found: + + wprint_in_middle(lesson_windows[i], 0, cell_width / 2, caption.length(), + caption.c_str(), COLOR_PAIR(0)); + wprint_in_middle(lesson_windows[i], 1, 1, start_time.length(), + start_time.c_str(), COLOR_PAIR(0)); + print_in_middle(lesson_windows[i], 1, cell_width / 2, 1, "-", + COLOR_PAIR(0)); + wprint_in_middle(lesson_windows[i], 1, cell_width - end_time.length() - 1, + end_time.length(), end_time.c_str(), COLOR_PAIR(0)); + wrefresh(lesson_windows[i]); + } + + for (uint8_t i = 0; i < num_of_days; i++) { + for (uint8_t j = 0; j < num_of_columns; j++) { + cells[i][j] = + newwin(cell_height, cell_width, i * cell_height + DEFAULT_OFFSET, + j * cell_width + DEFAULT_OFFSET); + box(cells[i][j], 0, 0); + wchar_t *string = L"test"; + wprint_in_middle(cells[i][j], 1, 0, wcslen(string), string, + COLOR_PAIR(0)); + wrefresh(cells[i][j]); + } + } refresh(); - getch(); // Wait for key press + getch(); +timetable_error_exit: + delete[] HourIdLookupTable; + delete[] day_windows; + delete[] lesson_windows; endwin(); } \ No newline at end of file