emmental/emmental/nowplaying/__init__.py

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."""