diff --git a/src/tt/controller/tasks.py b/src/tt/controller/tasks.py index 028f3c4..fe136ba 100644 --- a/src/tt/controller/tasks.py +++ b/src/tt/controller/tasks.py @@ -84,8 +84,8 @@ def get_tasks( query = query.where(fn.Lower(Task.text).contains(search_text.lower())) if statuses: query = query.where(Task.status.in_(statuses)) - #if projects: - # query = query.where(Task.project.in_(projects)) + if projects: + query = query.where(Task.project.in_(projects)) sort_expressions = _parse_sort_string(sort, statuses) query = query.order_by(*sort_expressions) diff --git a/src/tt/tui/editor.py b/src/tt/tui/editor.py index 07b769e..0bf0e53 100644 --- a/src/tt/tui/editor.py +++ b/src/tt/tui/editor.py @@ -83,7 +83,7 @@ class EnumColumnConfig(TableColumnConfig): class DateColumnConfig(TableColumnConfig): def preprocess(self, val): try: - return datetime.strptime(val, "%Y-%m-%d") + return datetime.datetime.strptime(val, "%Y-%m-%d") except ValueError: raise NotifyValidationError("Invalid date format. Use YYYY-MM-DD") diff --git a/src/tt/tui/keymodal.py b/src/tt/tui/keymodal.py index 23ed577..906ae98 100644 --- a/src/tt/tui/keymodal.py +++ b/src/tt/tui/keymodal.py @@ -37,6 +37,7 @@ class KeyModal(ModalScreen): for binding in self.app.BINDINGS: if binding[0] not in ["h", "j", "k", "l", "g", "G", "escape"]: table.add_row(binding[0], binding[2]) + # TODO: MRO? yield Static("tt keybindings", classes="title") yield Static(table) diff --git a/src/tt/tui/modals.py b/src/tt/tui/modals.py index 631546f..7e741b2 100644 --- a/src/tt/tui/modals.py +++ b/src/tt/tui/modals.py @@ -1,9 +1,10 @@ +import datetime from textual.screen import ModalScreen from textual.binding import Binding -from textual.widgets import RadioSet, RadioButton, Label -from .. import config +from textual.widgets import Label from ..utils import get_color_enum + class ConfirmModal(ModalScreen): CSS = """ ConfirmModal { @@ -42,42 +43,56 @@ class ChoiceModal(ModalScreen): ChoiceModal Label { height: 1; } + ChoiceModal Label#selected { + background: white; + + } """ BINDINGS = [ ("j,tab", "cursor_down", "Down"), - ("k", "cursor_up", "Up"), - Binding("enter", "select", "Select", priority=False), + ("k,shift+tab", "cursor_up", "Up"), + Binding("enter", "select", "Select", priority=True), ("escape", "cancel", "cancel"), ] def __init__(self, enum, selected): self._enum = enum - self.selected = selected + self.enum_by_idx = list(self._enum) + # selection index + self.sel_idx = 0 + # convert value back to index for initial selection + for idx, e in enumerate(self._enum): + if e.value == selected: + self.sel_idx = idx + break super().__init__() def compose(self): - yield RadioSet( - *[ - RadioButton( - get_color_enum(e.value, config.STATUSES), value=self.selected == str(e.value) - ) - for e in self._enum - ] - ) + for idx, e in enumerate(self._enum): + yield Label( + ("> " if idx == self.sel_idx else " ") + + get_color_enum(e.value, self._enum), + classes="selected" if idx == self.sel_idx else "", + ) + + def _move_cursor(self, dir): + labels = self.query(Label) + # reset old + labels[self.sel_idx].update(" " + get_color_enum(self.enum_by_idx[self.sel_idx], self._enum)) + # move cursor + self.sel_idx = (self.sel_idx + dir) % len(self._enum) + # reset new + labels[self.sel_idx].update("> " + get_color_enum(self.enum_by_idx[self.sel_idx], self._enum)) def action_cursor_down(self): - self.query_one(RadioSet).action_next_button() + self._move_cursor(1) def action_cursor_up(self): - self.query_one(RadioSet).action_previous_button() + self._move_cursor(-1) - def action_select(self): - rs = self.query_one(RadioSet) - # TODO: this doesn't work - #rs.action_toggle_button() - pressed = rs.pressed_button - self.dismiss(str(pressed.label)) + async def action_select(self): + self.dismiss(self.enum_by_idx[self.sel_idx]) def action_cancel(self): self.app.pop_screen() @@ -101,14 +116,18 @@ class DateModal(ModalScreen): BINDINGS = [ ("j", "cursor_down", "Down"), ("k", "cursor_up", "Up"), - ("h,tab", "cursor_left", "Left"), - ("l", "cursor_right", "Right"), + ("h,shift+tab", "cursor_left", "Left"), + ("l,tab", "cursor_right", "Right"), Binding("enter", "select", "Select", priority=True), ("escape", "cancel", "cancel"), ] def __init__(self, date): - self.pieces = [int(p) for p in date.split("-")] + if date: + self.pieces = [int(p) for p in date.split("-")] + else: + today = datetime.date.today() + self.pieces = [today.year, today.month, today.day] self.selected = 1 # start on month super().__init__() @@ -178,8 +197,7 @@ class DateModal(ModalScreen): event.prevent_default() def action_select(self): - date = "-".join(str(p) for p in self.pieces) - self.dismiss(date) + self.dismiss("-".join(str(p) for p in self.pieces)) def action_cancel(self): self.app.pop_screen() diff --git a/src/tt/tui/tasks.py b/src/tt/tui/tasks.py index e4bf809..f2313ce 100644 --- a/src/tt/tui/tasks.py +++ b/src/tt/tui/tasks.py @@ -56,10 +56,8 @@ class TT(TableEditor): def refresh_items(self): items = get_tasks( self.search_query, - projects=self.filters.get("project", "").split(","), - statuses=self.filters.get("status", "").split(",") - if "status" in self.filters - else None, + projects=self._filters_to_list("project"), + statuses=self._filters_to_list("status"), sort=self.sort_string, ) for item in items: @@ -68,6 +66,12 @@ class TT(TableEditor): key=str(item.id), ) + def _filters_to_list(self, key): + filters = self.filters.get(key) + if filters: + return filters.split(",") + else: + return None def run(default_view): app = TT(default_view)