def _chat_attributes(self, is_selected: bool = False) -> Tuple[int, ...]: attrs = ( get_color(cyan, -1), get_color(blue, -1), self._msg_color(is_selected), ) if is_selected: return tuple(attr | reverse for attr in attrs) return attrs
def _msg_attributes(self, is_selected: bool) -> Tuple[int, ...]: attrs = ( get_color(cyan, -1), get_color(blue, -1), get_color(yellow, -1), get_color(white, -1), ) if is_selected: return tuple(attr | reverse for attr in attrs) return attrs
def _chat_attributes(self, is_selected: bool, title: str, user: Optional[str]) -> Tuple[int, ...]: attrs = ( get_color(cyan, -1), get_color(get_color_by_str(title), -1), get_color(get_color_by_str(user or ""), -1), self._msg_color(is_selected), ) if is_selected: return tuple(attr | reverse for attr in attrs) return attrs
def __init__( self, stdscr: window, chat_view: "ChatView", msg_view: "MsgView", status_view: "StatusView", ) -> None: curses.noecho() curses.cbreak() stdscr.keypad(True) curses.curs_set(0) curses.start_color() curses.use_default_colors() # init white color first to initialize colors correctly get_color(white, -1) self.stdscr = stdscr self.chats = chat_view self.msgs = msg_view self.status = status_view self.max_read = 2048
def draw( self, current_msg_idx: int, msgs: List[Tuple[int, Dict[str, Any]]], min_msg_padding: int, chat: Dict[str, Any], ) -> None: self.win.erase() msgs_to_draw = self._collect_msgs_to_draw( current_msg_idx, msgs, min_msg_padding ) if not msgs_to_draw: log.error("Can't collect message for drawing!") for elements, selected, line_num in msgs_to_draw: column = 0 user = elements[1] for attr, elem in zip( self._msg_attributes(selected, user), elements ): if not elem: continue lines = (column + len(elem)) // self.w last_line = self.h == line_num + lines # work around agaist curses behaviour, when you cant write # char to the lower right coner of the window # see https://stackoverflow.com/questions/21594778/how-to-fill-to-lower-right-corner-in-python-curses/27517397#27517397 if last_line: start, stop = 0, self.w - column for i in range(lines): # insstr does not wraps long strings self.win.insstr( line_num + i, column if not i else 0, elem[start:stop], attr, ) start, stop = stop, stop + self.w else: self.win.addstr(line_num, column, elem, attr) column += len(elem) self.win.addstr( 0, 0, self._msg_title(chat), get_color(cyan, -1) | bold ) self._refresh()
def draw(self, current: int, chats: List[Dict[str, Any]], title: str = "Chats") -> None: self.win.erase() line = curses.ACS_VLINE # type: ignore width = self.w - 1 self.win.vline(0, width, line, self.h) self.win.addstr(0, 0, title.center(width)[:width], get_color(cyan, -1) | bold) for i, chat in enumerate(chats, 1): is_selected = i == current + 1 date = get_date(chat) title = chat["title"] offset = 0 last_msg_sender, last_msg = self._get_last_msg_data(chat) sender_label = f" {last_msg_sender}" if last_msg_sender else "" flags = self._get_flags(chat) flags_len = string_len_dwc(flags) if flags: self.win.addstr( i, max(0, width - flags_len), truncate_to_len(flags, width)[-width:], # flags[-width:], self._unread_color(is_selected), ) for attr, elem in zip( self._chat_attributes(is_selected, title, last_msg_sender), [f"{date} ", title, sender_label, f" {last_msg}"], ): if not elem: continue item = truncate_to_len(elem, max(0, width - offset - flags_len)) if len(item) > 1: self.win.addstr(i, offset, item, attr) offset += string_len_dwc(elem) self._refresh()
def _unread_color(self, is_selected: bool = False) -> int: color = get_color(magenta, -1) if is_selected: return color | reverse return color
def _msg_color(self, is_selected: bool = False) -> int: color = get_color(white, -1) if is_selected: return color | reverse return color