emmental/emmental/sidebar/icon.py
Anna Schumaker a4f30d87e6 sidebar: Use the Texture Cache for album art and user icons
I make sure to clear an existing texture before setting a new one in
case the user downloads a new file with the same path. Otherwise we'll
end up using a stale texture in the list.

Implements: #54 ("Convert the SideBar to use the Texture Cache")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-10-20 16:31:37 -04:00

75 lines
2.6 KiB
Python

# Copyright 2022 (c) Anna Schumaker.
"""Custom icon widgets for playlist rows."""
import pathlib
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gio
from gi.repository import Gtk
from gi.repository import Adw
from .. import texture
IMAGE_FILTERS = Gio.ListStore()
IMAGE_FILTERS.append(Gtk.FileFilter(name="Image Files",
mime_types=["inode/directory"]))
IMAGE_FILTERS[0].add_pixbuf_formats()
class Icon(Adw.Bin):
"""A custom Adw.Avatar that can load images from a file path."""
text = GObject.Property(type=str)
filepath = GObject.Property(type=GObject.TYPE_PYOBJECT)
icon_name = GObject.Property(type=str)
show_initials = GObject.Property(type=bool, default=False)
def __init__(self, **kwargs):
"""Initialize our Playlist icon."""
super().__init__(**kwargs)
self._icon = Adw.Avatar(size=40, show_initials=self.show_initials)
self.bind_property("text", self._icon, "text")
self.bind_property("icon-name", self._icon, "icon-name")
self.bind_property("show-initials", self._icon, "show-initials")
self.connect("notify::filepath", self.__notify_filepath)
self.set_child(self._icon)
def __notify_filepath(self, icon: Adw.Bin, param) -> None:
self._icon.set_custom_image(texture.CACHE[self.filepath])
class Settable(Icon):
"""A custom Avatar with an attached popover for selecting an image."""
settable = GObject.Property(type=bool, default=False)
def __init__(self):
"""Initialize our settable icon."""
super().__init__()
self._dialog = Gtk.FileDialog(title="Pick an Image",
filters=IMAGE_FILTERS)
self._long_press = Gtk.GestureLongPress()
self._long_press.connect("pressed", self.__long_press)
self.add_controller(self._long_press)
def __async_ready(self, dialog: Gtk.FileDialog, task: Gio.Task) -> None:
try:
file = dialog.open_finish(task)
path = pathlib.Path(file.get_path())
texture.CACHE.drop(path)
self.filepath = path
except GLib.Error:
self.filepath = None
def __long_press(self, gesture: Gtk.GestureLongPress,
x: float, y: float) -> None:
"""Handle a click event."""
if self.settable:
if self.filepath is not None:
file = Gio.File.new_for_path(str(self.filepath))
self._dialog.set_initial_file(file)
self._dialog.open(self.get_ancestor(Gtk.Window), None,
self.__async_ready)