# Copyright 2022 (c) Anna Schumaker. """A card for displaying information about the currently playing track.""" from gi.repository import GObject from gi.repository import Gtk from ..action import ActionEntry from .. import buttons from . import artwork from . import controls from . import seeker from . import tags class Card(Gtk.Box): """The Now Playing information card.""" artwork = GObject.Property(type=GObject.TYPE_PYOBJECT) title = GObject.Property(type=str) album = GObject.Property(type=str) artist = GObject.Property(type=str) album_artist = GObject.Property(type=str) favorite = GObject.Property(type=bool, default=False) duration = GObject.Property(type=float, default=1) position = GObject.Property(type=float, default=0) prefer_artist = GObject.Property(type=bool, default=True) playing = GObject.Property(type=bool, default=False) autopause = GObject.Property(type=int, default=-1, minimum=-1, maximum=99) have_next = GObject.Property(type=bool, default=False) have_previous = GObject.Property(type=bool, default=False) have_track = GObject.Property(type=bool, default=False) have_db_track = GObject.Property(type=bool, default=False) editing = GObject.Property(type=bool, default=False) def __init__(self): """Initialize a Now Playing Card.""" super().__init__() self._grid = Gtk.Grid() self._artwork = artwork.Artwork() self._tags = tags.TagInfo() self._controls = controls.Controls() self._bottom_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) self._favorite = buttons.ImageToggle("heart-filled", "heart-outline-thick-symbolic", "remove from 'Favorite Tracks'", "add to 'Favorite Tracks'", large_icon=True, has_frame=False, sensitive=False, valign=Gtk.Align.CENTER) self._jump = buttons.Button(icon_name="arrow4-down-symbolic", tooltip_text="scroll to current track", large_icon=True, sensitive=False, has_frame=False, valign=Gtk.Align.CENTER) self._seeker = seeker.Scale(sensitive=False) self.bind_property("artwork", self._artwork, "filepath") for prop in ["title", "album", "artist", "album-artist"]: self.bind_property(prop, self._tags, prop) self.bind_property("prefer-artist", self._tags, "prefer-artist", GObject.BindingFlags.BIDIRECTIONAL) for prop in ["playing", "editing", "have-next", "have-previous", "have-track"]: self.bind_property(prop, self._controls, prop) self.bind_property("have-db-track", self._jump, "sensitive") self.bind_property("have-db-track", self._favorite, "sensitive") self.bind_property("have-track", self._seeker, "sensitive") self.bind_property("autopause", self._controls, "autopause", GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("favorite", self._favorite, "active", GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("duration", self._seeker, "duration") self.bind_property("position", self._seeker, "position") for sig in ["play", "pause", "previous", "next"]: self._controls.connect(sig, self.__on_control, sig) self._jump.connect("clicked", self.__on_jump) self._seeker.connect("change-value", self.__on_seek) self._bottom_box.append(self._favorite) self._bottom_box.append(self._jump) self._bottom_box.append(self._seeker) self._grid.attach(self._tags, 0, 0, 1, 1) self._grid.attach(self._controls, 1, 0, 1, 1) self._grid.attach(self._bottom_box, 0, 1, 2, 1) self.append(self._artwork) self.append(self._grid) self.add_css_class("card") def __on_control(self, controls: controls.Controls, signal: str) -> None: self.emit(signal) def __on_jump(self, jump: Gtk.Button) -> None: self.emit("jump") def __on_seek(self, seek: seeker.Scale, scroll: Gtk.ScrollType, value: float) -> None: self.emit("seek", value) @property def accelerators(self) -> list[ActionEntry]: """Get a list of accelerators for the Now Playing card.""" return [ActionEntry("toggle-favorite", self._favorite.activate, "f", enabled=(self, "have-db-track")), ActionEntry("goto-current-track", self._jump.activate, "g", enabled=(self, "have-db-track")), ActionEntry("next-track", self._controls.activate_next, "Return", enabled=(self._controls, "can-activate-next")), ActionEntry("previous-track", self._controls.activate_previous, "BackSpace", enabled=(self._controls, "can-activate-prev")), ActionEntry("play-pause", self._controls.activate_play_pause, "space", enabled=(self._controls, "can-activate-play-pause")), ActionEntry("inc-autopause", self._controls.increase_autopause, "plus", "KP_Add", enabled=(self, "playing")), ActionEntry("dec-autopause", self._controls.decrease_autopause, "minus", "KP_Subtract", enabled=(self, "playing"))] @GObject.Signal def jump(self) -> None: """Signal that the Tracklist should be scrolled.""" @GObject.Signal def play(self) -> None: """Signal that the Play button has been clicked.""" @GObject.Signal def pause(self) -> None: """Signal that the Pause button has been clicked.""" @GObject.Signal def previous(self) -> None: """Signal that the Previous button has been clicked.""" @GObject.Signal def next(self) -> None: """Signal that the Nause button has been clicked.""" @GObject.Signal(arg_types=(float,)) def seek(self, newpos: float) -> None: """Signal that the user wants us to seek."""