diff options
Diffstat (limited to 'girok/utils/display.py')
-rw-r--r-- | girok/utils/display.py | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/girok/utils/display.py b/girok/utils/display.py new file mode 100644 index 0000000..ad44329 --- /dev/null +++ b/girok/utils/display.py @@ -0,0 +1,253 @@ +from datetime import datetime +import calendar + +from rich import print +from rich.console import Console +from rich.tree import Tree +from rich.align import Align +from rich import box +from rich.style import Style +from rich.table import Table, Column +from rich.text import Text +from rich.align import Align +import shutil + +import girok.utils.task as task_utils +import girok.utils.calendar as calendar_utils +import girok.utils.general as general_utils +from girok.config import get_config +import girok.constants as constants + +console = Console() +cfg = get_config() + +def display_categories(cats_dict: dict, highlight_cat=None): + tree = Tree("") + for idx, cat in enumerate(cats_dict): + display_category( + cats_dict, + cat, + top_most=True, + tree=tree, + cumul_path=cat, + highlight_cat=highlight_cat, + color=cats_dict[cat]['color'] + ) + console.print(tree) + + +def display_category( + cats_dict: dict, + cat: str, + top_most=True, + tree: Tree=None, + cumul_path="", + highlight_cat=None, + color=None, +): + style = Style( + color=constants.TABLE_HEADER_COLOR if highlight_cat != cumul_path else "#B9D66A", + bold=True + ) + # if not top_most: + # style = Style(color=constants.TABLE_TASK_NAME_COLOR, bold=True) + + # if top_most: + circle = Text(constants.CIRCLE_EMOJI + " ", style=Style(color=constants.CIRCLE_COLOR[color])) + + dir_name = Text(f"{cat}", style=style) + # if top_most: + dir_name = Text.assemble(circle, dir_name) + + tree = tree.add(dir_name) + for sub in cats_dict[cat]['subcategories'].keys(): + display_category( + cats_dict[cat]['subcategories'], + sub, + top_most=False, + tree=tree, + cumul_path=cumul_path + "/" + sub, + highlight_cat=highlight_cat, + color=color + ) + + +def center_print(text, type: str = None, wrap: bool = False): + if type == "title": + style = Style( + color=constants.DISPLAY_TERMINAL_COLOR_TITLE_TEXT, + bgcolor=constants.DISPLAY_TERMINAL_COLOR_TITLE_BACKGROUND + ) + elif type == "success": + style = Style( + color=constants.DISPLAY_TERMINAL_COLOR_SUCCESS_TEXT, + bgcolor=constants.DISPLAY_TERMINAL_COLOR_SUCCESS_BACKGROUND + ) + elif type == "error": + style = Style( + color=constants.DISPLAY_TERMINAL_COLOR_ERROR_TEXT, + bgcolor=constants.DISPLAY_TERMINAL_COLOR_ERROR_BACKGROUND + ) + elif type == "warning": + style = Style( + color=constants.DISPLAY_TERMINAL_COLOR_WARNING_TEXT, + bgcolor=constants.DISPLAY_TERMINAL_COLOR_WARNING_BACKGROUND + ) + else: + style = Style( + color=constants.DISPLAY_TERMINAL_COLOR_TITLE_TEXT, + bgcolor=constants.DISPLAY_TERMINAL_COLOR_TITLE_BACKGROUND + ) + if wrap: + width = shutil.get_terminal_size().columns // 2 + else: + width = shutil.get_terminal_size().columns + + content = Text(text, style=style) + console.print(Align.center(content, style=style, width=width), height=100) + + +def display_tasks_by_category( + task_tree, + color_dict, + marked_task_id: int = None, + marked_color: str = constants.TABLE_TASK_DELETED_COLOR +): + # print(task_tree) + task_ids_cache = {} + tree = Tree("") + for idx, cat_name in enumerate(task_tree): + tree.add(display_category_with_tasks( + cat_name=cat_name, + task_tree=task_tree[cat_name], + color_dict=color_dict, + top_most=True, + task_ids_cache=task_ids_cache, + marked_task_id=marked_task_id, + marked_color=marked_color + )) + general_utils.cache_task_ids(cfg=cfg, cache=task_ids_cache) + return tree + + +def display_category_with_tasks( + cat_name, + task_tree: dict, + color_dict, + top_most, + task_ids_cache, + marked_task_id: int = None, + marked_color: str = constants.TABLE_TASK_DELETED_COLOR, +): + dir_name = Text(f"{cat_name}", style=Style(color=constants.TABLE_HEADER_COLOR, bold=True)) + dir_name = Text.assemble( + Text(f"{constants.CIRCLE_EMOJI} ", style=Style(color=constants.CIRCLE_COLOR[color_dict[cat_name]])), + dir_name + ) + + tree = Tree(dir_name) + + for sub_cat_name in task_tree['sub_categories']: + sub_tree = display_category_with_tasks( + cat_name=sub_cat_name, + task_tree=task_tree['sub_categories'][sub_cat_name], + color_dict=color_dict, + top_most=False, + task_ids_cache=task_ids_cache, + marked_task_id=marked_task_id, + marked_color=marked_color + ) + tree.add(sub_tree) + + for task in task_tree['tasks']: + # Cache task id + if not(task['task_id'] == marked_task_id and marked_color == constants.TABLE_TASK_DELETED_COLOR): + task_ids_cache[len(task_ids_cache) + 1] = task['task_id'] + + deadline = datetime.strptime(task['deadline'], "%Y-%m-%dT%H:%M:%S") + year, month, day = deadline.year, deadline.month, deadline.day + h, m, s = str(deadline.time()).split(":") + + weekday_name = task_utils.get_weekday_name_from_date(year, month, day) + + h = int(h) + is_time = task['is_time'] + afternoon = h >= 12 + if h > 12: + h -= 12 + + time = f" / {h}:{m} {'PM' if afternoon else 'AM'}" if is_time else '' + remaining_days = task_utils.get_day_offset_between_two_dates(datetime.now(), deadline) + day_offset_message = f"{remaining_days} days left" if remaining_days > 0 else f"{abs(remaining_days)} days passed" + + if remaining_days == 0: + day_offset_message = "Due Today" + + if not(task['task_id'] == marked_task_id and marked_color == constants.TABLE_TASK_DELETED_COLOR): + task_id = Text(f"[{len(task_ids_cache)}] ", style=Style(color="white" if task['task_id'] != marked_task_id else marked_color)) + else: + task_id = "" + task_name = Text(task['name'], style=Style(color=constants.TABLE_TASK_NAME_COLOR if task['task_id'] != marked_task_id else marked_color, bold=True)) + task_remaining_days = Text(f" [{day_offset_message}]", style=Style(color='#F5F7F2' if task['task_id'] != marked_task_id else marked_color)) + task_date = Text(f" - {year}/{month}/{day} {weekday_name}", style=Style(color="white" if task['task_id'] != marked_task_id else marked_color)) + node_name = Text.assemble(task_id, task_name, task_remaining_days, task_date, style=Style(strike=True if task['task_id'] == marked_task_id and marked_color == constants.TABLE_TASK_DELETED_COLOR else False)) + + tree.add(node_name) + + return tree + + +def display_tasks_by_list(tasks: list, marked_task_id: int = None, color: str = constants.TABLE_TASK_DELETED_COLOR): + table = build_task_table(tasks, marked_task_id, color) + print(Align(table, align="center")) + + +def build_task_table(tasks: list, marked_task_id: int = None, color: str = constants.TABLE_TASK_DELETED_COLOR): + tasks = sorted(tasks, key=lambda x: calendar_utils.get_date_obj_from_str_separated_by_T(x['deadline'])) + num_tasks = len(tasks) + table = Table( + Column(header="ID", justify="center", header_style=Style(color=constants.TABLE_HEADER_COLOR), style=Style(color=constants.TABLE_TASK_NAME_COLOR)), + Column(header="Name", header_style=Style(color=constants.TABLE_HEADER_COLOR), style=Style(color=constants.TABLE_TASK_NAME_COLOR)), + Column(header="Category", justify="center", header_style=Style(color=constants.TABLE_HEADER_COLOR), style=Style(color=constants.TABLE_TEXT_COLOR)), + Column(header="Deadline", justify="center", header_style=Style(color=constants.TABLE_HEADER_COLOR), style=Style(color="green")), + Column(header="Tag", justify="center", header_style=Style(color=constants.TABLE_HEADER_COLOR), style=Style(color=constants.TABLE_TEXT_COLOR)), + Column(header="Priority", justify="center", header_style=Style(color=constants.TABLE_HEADER_COLOR), style=Style(color=constants.TABLE_TEXT_COLOR)), + Column(header="Remaining", justify="center", header_style=Style(color=constants.TABLE_HEADER_COLOR), style=Style(color=constants.TABLE_TEXT_COLOR)), + box=box.SIMPLE_HEAVY, + show_lines=False if num_tasks > 15 else True, + border_style=Style(color="#D7E1C9", bold=True) + ) + + task_ids_cache = {} + for idx, task in enumerate(tasks): + # Cache task id + task_ids_cache[idx + 1] = task['task_id'] + + date = calendar_utils.get_date_obj_from_str_separated_by_T(task['deadline']) + deadline = f"{date.day} {calendar.month_name[date.month]} {date.year}" + remaining_days = task_utils.get_day_offset_between_two_dates(datetime.now(), date) + day_offset_message = f"{remaining_days} days left" if remaining_days > 0 else f"{abs(remaining_days)} days passed" + if remaining_days == 0: + day_offset_message = "Due Today" + circle = Text(constants.CIRCLE_EMOJI + " ", style=Style(color=constants.CIRCLE_COLOR[task['color']])) + task_name = Text.assemble(circle, task['name'], style=Style(color=color if marked_task_id == task['task_id'] else constants.TABLE_TASK_NAME_COLOR, bold=True)) + + table.add_row( + Text(str(idx + 1), style=Style(color=color if marked_task_id == task['task_id'] else constants.TABLE_TEXT_COLOR)), + task_name, + Text(task['task_category_full_path'] if task['task_category_full_path'] else "None", style=Style(color=color if marked_task_id == task['task_id'] else constants.TABLE_TEXT_COLOR)), + Text(deadline, style=Style(color=color if marked_task_id == task['task_id'] else constants.TABLE_DEADLINE_COLOR)), + Text(task['tag'] if task['tag'] else '-', style=Style(color=color if marked_task_id == task['task_id'] else constants.TABLE_TEXT_COLOR)), + Text(str(task['priority']) if task['priority'] else '-', style=Style(color=color if marked_task_id == task['task_id'] else constants.TABLE_TEXT_COLOR)), + Text(day_offset_message, style=Style(color=color if marked_task_id == task['task_id'] else constants.TABLE_TEXT_COLOR)) + ) + + general_utils.cache_task_ids(cfg=cfg, cache=task_ids_cache) + + return table + + + + + + |