Skip to content

Commit

Permalink
Tag Window
Browse files Browse the repository at this point in the history
Use reusable Tag Window instead of a Popover for each task

Signed-off-by: Simó Albert i Beltran <[email protected]>
  • Loading branch information
sim6 committed May 24, 2024
1 parent 872a8c0 commit dcd10d3
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 105 deletions.
4 changes: 4 additions & 0 deletions errands/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
ErrandsAttachmentsWindow,
ErrandsNotesWindow,
PriorityWindow,
TagWindow,
)
from errands.widgets.sidebar import Sidebar
from errands.widgets.tags.tags import Tags
Expand Down Expand Up @@ -72,6 +73,7 @@ class State:
attachments_window: ErrandsAttachmentsWindow | None = None

priority_window: PriorityWindow | None = None
tag_window: TagWindow | None = None

@classmethod
def init(cls) -> None:
Expand All @@ -80,12 +82,14 @@ def init(cls) -> None:
ErrandsDateTimeWindow,
ErrandsAttachmentsWindow,
PriorityWindow,
TagWindow,
)

cls.notes_window = ErrandsNotesWindow()
cls.datetime_window = ErrandsDateTimeWindow()
cls.attachments_window = ErrandsAttachmentsWindow()
cls.priority_window = PriorityWindow()
cls.tag_window = TagWindow()

@classmethod
def get_task_list(cls, uid: str) -> TaskList:
Expand Down
1 change: 1 addition & 0 deletions errands/widgets/shared/task_toolbar/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
from errands.widgets.shared.task_toolbar.datetime_window import ErrandsDateTimeWindow
from errands.widgets.shared.task_toolbar.notes_window import ErrandsNotesWindow
from errands.widgets.shared.task_toolbar.priority_window import PriorityWindow
from errands.widgets.shared.task_toolbar.tag_window import TagWindow
139 changes: 139 additions & 0 deletions errands/widgets/shared/task_toolbar/tag_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Copyright 2024 Vlad Krupinskii <[email protected]>
# SPDX-License-Identifier: MIT

from __future__ import annotations

from typing import TYPE_CHECKING

from gi.repository import Adw, Gtk, GObject # type:ignore

from errands.lib.data import UserData
from errands.lib.logging import Log
from errands.lib.utils import get_children
from errands.lib.sync.sync import Sync
from errands.state import State
from errands.widgets.shared.components.boxes import ErrandsBox
from errands.widgets.shared.components.buttons import ErrandsCheckButton
from errands.widgets.shared.components.toolbar_view import ErrandsToolbarView

if TYPE_CHECKING:
from errands.widgets.task import Task
from errands.widgets.today.today_task import TodayTask


class TagWindow(Adw.Dialog):
def __init__(self):
super().__init__()
self.__build_ui()

# ------ PRIVATE METHODS ------ #

def __build_ui(self) -> None:
self.set_follows_content_size(True)
self.set_title(_("Tags"))

tags_status_page: Adw.StatusPage = Adw.StatusPage(
title=_("No Tags"),
icon_name="errands-info-symbolic",
css_classes=["compact"],
)
self.tags_list: Gtk.Box = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
spacing=6,
margin_bottom=6,
margin_end=6,
margin_start=6,
margin_top=6,
)
self.tags_list.bind_property(
"visible",
tags_status_page,
"visible",
GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN,
)

self.set_child(
ErrandsToolbarView(
top_bars=[Adw.HeaderBar()],
top_bar_style=Adw.ToolbarStyle.RAISED,
content=Gtk.ScrolledWindow(
width_request=200,
propagate_natural_height=True,
propagate_natural_width=True,
vexpand=True,
child=ErrandsBox(
orientation=Gtk.Orientation.VERTICAL,
vexpand=True,
valign=Gtk.Align.CENTER,
children=[self.tags_list, tags_status_page],
),
),
)
)

# ------ PUBLIC METHODS ------ #

def show(self, task: Task | TodayTask):
self.task = task
tags: list[str] = [t.text for t in UserData.tags]
tags_list_items: list[ErrandsToolbarTagsListItem] = get_children(self.tags_list)
tags_list_items_text = [t.title for t in tags_list_items]

# Remove tags
for item in tags_list_items:
if item.title not in tags:
self.tags_list.remove(item)

# Add tags
for tag in tags:
if tag not in tags_list_items_text:
self.tags_list.append(ErrandsToolbarTagsListItem(tag, self))

# Toggle tags
task_tags: list[str] = [t.title for t in self.task.tags]
tags_items: list[ErrandsToolbarTagsListItem] = get_children(self.tags_list)
for t in tags_items:
t.block_signals = True
t.toggle_btn.set_active(t.title in task_tags)
t.block_signals = False

self.tags_list.set_visible(len(get_children(self.tags_list)) > 0)
self.present(State.main_window)


class ErrandsToolbarTagsListItem(Gtk.Box):
block_signals = False

def __init__(self, title: str, tag_window: TagWindow) -> None:
super().__init__()
self.set_spacing(6)
self.title = title
self.tag_window = tag_window
self.toggle_btn = ErrandsCheckButton(on_toggle=self.__on_toggle)
self.append(self.toggle_btn)
self.append(
Gtk.Label(
label=title, hexpand=True, halign=Gtk.Align.START, max_width_chars=20
)
)
self.append(
Gtk.Image(icon_name="errands-tag-symbolic", css_classes=["dim-label"])
)

def __on_toggle(self, btn: Gtk.CheckButton) -> None:
if self.block_signals:
return
task = self.tag_window.task

tags: list[str] = task.task_data.tags

if btn.get_active():
if self.title not in tags:
tags.append(self.title)
else:
if self.title in tags:
tags.remove(self.title)

task.update_props(["tags", "synced"], [tags, False])
task.update_tags_bar()
Sync.sync()
109 changes: 4 additions & 105 deletions errands/widgets/shared/task_toolbar/toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@

from gi.repository import Adw, Gio, GLib, GObject, Gtk # type:ignore

from errands.lib.data import UserData
from errands.lib.logging import Log
from errands.lib.sync.sync import Sync
from errands.lib.utils import get_children, get_human_datetime
from errands.lib.utils import get_human_datetime
from errands.state import State
from errands.widgets.shared.color_selector import ErrandsColorSelector
from errands.widgets.shared.components.boxes import ErrandsBox
Expand Down Expand Up @@ -70,49 +69,13 @@ def __build_ui(self) -> None:
)

# Tags button
tags_status_page: Adw.StatusPage = Adw.StatusPage(
title=_("No Tags"),
icon_name="errands-info-symbolic",
css_classes=["compact"],
)
self.tags_list: Gtk.Box = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
spacing=6,
margin_bottom=6,
margin_end=6,
margin_start=6,
margin_top=6,
)
self.tags_list.bind_property(
"visible",
tags_status_page,
"visible",
GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN,
)
self.tags_btn: Gtk.MenuButton = Gtk.MenuButton(
tag_btn: ErrandsButton = ErrandsButton(
valign=Gtk.Align.CENTER,
icon_name="errands-tag-add-symbolic",
tooltip_text=_("Tags"),
css_classes=["flat"],
popover=Gtk.Popover(
css_classes=["tags-menu"],
child=Gtk.ScrolledWindow(
max_content_width=200,
max_content_height=200,
width_request=200,
propagate_natural_height=True,
propagate_natural_width=True,
vexpand=True,
child=ErrandsBox(
orientation=Gtk.Orientation.VERTICAL,
vexpand=True,
valign=Gtk.Align.CENTER,
children=[self.tags_list, tags_status_page],
),
),
),
on_click=lambda *_: State.tag_window.show(self.task),
)
self.tags_btn.connect("notify::active", self._on_tags_btn_toggled)

self.attachments_btn: ErrandsButton = ErrandsButton(
tooltip_text=_("Attachments"),
Expand Down Expand Up @@ -184,7 +147,7 @@ def __build_ui(self) -> None:
children=[
self.notes_btn,
self.priority_btn,
self.tags_btn,
tag_btn,
self.attachments_btn,
menu_btn,
],
Expand Down Expand Up @@ -259,67 +222,3 @@ def _on_menu_toggled(self, btn: Gtk.MenuButton, active: bool) -> None:
self.task.block_signals = True
self.color_selector.select_color(self.task.task_data.color)
self.task.block_signals = False

def _on_tags_btn_toggled(self, btn: Gtk.MenuButton, *_) -> None:
if not btn.get_active():
return
tags: list[str] = [t.text for t in UserData.tags]
tags_list_items: list[ErrandsToolbarTagsListItem] = get_children(self.tags_list)
tags_list_items_text = [t.title for t in tags_list_items]

# Remove tags
for item in tags_list_items:
if item.title not in tags:
self.tags_list.remove(item)

# Add tags
for tag in tags:
if tag not in tags_list_items_text:
self.tags_list.append(ErrandsToolbarTagsListItem(tag, self.task))

# Toggle tags
task_tags: list[str] = [t.title for t in self.task.tags]
tags_items: list[ErrandsToolbarTagsListItem] = get_children(self.tags_list)
for t in tags_items:
t.block_signals = True
t.toggle_btn.set_active(t.title in task_tags)
t.block_signals = False

self.tags_list.set_visible(len(get_children(self.tags_list)) > 0)


class ErrandsToolbarTagsListItem(Gtk.Box):
block_signals = False

def __init__(self, title: str, task: Task) -> None:
super().__init__()
self.set_spacing(6)
self.title = title
self.task = task
self.toggle_btn = ErrandsCheckButton(on_toggle=self.__on_toggle)
self.append(self.toggle_btn)
self.append(
Gtk.Label(
label=title, hexpand=True, halign=Gtk.Align.START, max_width_chars=20
)
)
self.append(
Gtk.Image(icon_name="errands-tag-symbolic", css_classes=["dim-label"])
)

def __on_toggle(self, btn: Gtk.CheckButton) -> None:
if self.block_signals:
return

tags: list[str] = self.task.task_data.tags

if btn.get_active():
if self.title not in tags:
tags.append(self.title)
else:
if self.title in tags:
tags.remove(self.title)

self.task.update_props(["tags", "synced"], [tags, False])
self.task.update_tags_bar()
Sync.sync()

0 comments on commit dcd10d3

Please sign in to comment.