145 lines
6.5 KiB
Python
145 lines
6.5 KiB
Python
# 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,
|
|
"<Control>f", enabled=(self, "have-db-track")),
|
|
ActionEntry("goto-current-track", self._jump.activate,
|
|
"<Control>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,
|
|
"<Control>plus", "<Control>KP_Add",
|
|
enabled=(self, "playing")),
|
|
ActionEntry("dec-autopause", self._controls.decrease_autopause,
|
|
"<Control>minus", "<Control>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."""
|