audio: Replace the old Controls widget with AudioControls
And grab the global Player instance during construction. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
ef1d3f0985
commit
76bf68f484
|
@ -1,14 +1,20 @@
|
|||
# Copyright 2021 (c) Anna Schumaker.
|
||||
import sys
|
||||
import tagdb
|
||||
from gi.repository import Gst
|
||||
from . import controls
|
||||
from . import nowplaying
|
||||
from . import player
|
||||
from . import scale
|
||||
|
||||
Gst.init(sys.argv)
|
||||
Player = player.Player()
|
||||
tagdb.Stack.Counter = Player.Autopause
|
||||
|
||||
|
||||
def AudioControls():
|
||||
return controls.AudioControls(Player, Player.Autopause)
|
||||
|
||||
def NowPlaying():
|
||||
return nowplaying.NowPlaying(Player)
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# Copyright 2021 (c) Anna Schumaker.
|
||||
from gi.repository import Gtk, Gst
|
||||
from . import menu
|
||||
from . import scale
|
||||
|
||||
class ControlButton(Gtk.Button):
|
||||
|
@ -130,40 +129,3 @@ class AudioControls(Gtk.Box):
|
|||
self.append(PlayPauseButton(player))
|
||||
self.append(NextButton(player))
|
||||
self.append(MenuButton(player, apscale))
|
||||
|
||||
|
||||
class Controls(Gtk.Box):
|
||||
def __init__(self):
|
||||
Gtk.Box.__init__(self)
|
||||
self.add_css_class("large-icons")
|
||||
self.add_css_class("linked")
|
||||
|
||||
self.previous = Gtk.Button.new_from_icon_name("media-skip-backward")
|
||||
self.append(self.previous)
|
||||
|
||||
self.play = Gtk.Button.new_from_icon_name("media-playback-start")
|
||||
self.append(self.play)
|
||||
|
||||
self.pause = Gtk.Button.new_from_icon_name("media-playback-pause")
|
||||
self.pause.hide()
|
||||
self.append(self.pause)
|
||||
|
||||
self.next = Gtk.Button.new_from_icon_name("media-skip-forward")
|
||||
self.append(self.next)
|
||||
|
||||
self.menu = menu.Button()
|
||||
self.append(self.menu)
|
||||
|
||||
self.sizegroup = Gtk.SizeGroup()
|
||||
self.sizegroup.add_widget(self)
|
||||
|
||||
def connect(self, name, func):
|
||||
if name == "volume-changed":
|
||||
self.menu.volume.connect("value-changed", func)
|
||||
else:
|
||||
button = self.__dict__.get(name)
|
||||
button.connect("clicked", func)
|
||||
|
||||
def set_state(self, state):
|
||||
self.play.set_visible(state != Gst.State.PLAYING)
|
||||
self.pause.set_visible(state == Gst.State.PLAYING)
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
# Copyright 2021 (c) Anna Schumaker.
|
||||
from lib import settings
|
||||
from gi.repository import Gtk
|
||||
import tagdb
|
||||
|
||||
class Button(Gtk.MenuButton):
|
||||
def __init__(self):
|
||||
Gtk.MenuButton.__init__(self)
|
||||
|
||||
self.count = Gtk.Label()
|
||||
self.count.set_yalign(0)
|
||||
self.count.set_markup("<small> </small>")
|
||||
|
||||
self.pause = Gtk.Image.new_from_icon_name("media-playback-start")
|
||||
self.counter = Gtk.Scale()
|
||||
self.counter.set_adjustment(tagdb.Stack.Counter)
|
||||
self.counter.connect("value-changed", self.on_counter_changed)
|
||||
self.counter.set_format_value_func(self.format_counter)
|
||||
self.counter.set_digits(0)
|
||||
self.counter.set_draw_value(True)
|
||||
|
||||
settings.initialize("audio.volume", 1.0)
|
||||
self.vol_img = Gtk.Image()
|
||||
self.volume = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL,
|
||||
0.0, 1.0, 0.05)
|
||||
self.volume.connect("value-changed", self.on_volume_changed)
|
||||
self.volume.set_value(settings.get_float("audio.volume"))
|
||||
self.volume.set_format_value_func(self.format_volume)
|
||||
self.volume.set_draw_value(True)
|
||||
self.on_volume_changed(self.volume)
|
||||
|
||||
self.grid = Gtk.Grid()
|
||||
self.grid.attach(self.pause, 0, 0, 1, 1)
|
||||
self.grid.attach(self.counter, 1, 0, 1, 1)
|
||||
self.grid.attach(self.vol_img, 0, 1, 1, 1)
|
||||
self.grid.attach(self.volume, 1, 1, 1, 1)
|
||||
self.grid.add_css_class("large-icons")
|
||||
self.grid.set_column_spacing(5)
|
||||
|
||||
self.popover = Gtk.Popover()
|
||||
self.popover.set_child(self.grid)
|
||||
|
||||
self.overlay = Gtk.Overlay()
|
||||
self.toggle = self.get_first_child()
|
||||
self.icon = self.toggle.get_child()
|
||||
self.icon.set_margin_top(5)
|
||||
self.toggle.set_child(self.overlay)
|
||||
self.overlay.add_overlay(self.count)
|
||||
self.overlay.add_overlay(self.icon)
|
||||
|
||||
self.set_popover(self.popover)
|
||||
self.add_css_class("normal-icons")
|
||||
|
||||
def format_counter(self, scale, value):
|
||||
value = int(value)
|
||||
if value == -1:
|
||||
return "Keep Playing"
|
||||
elif value == 0:
|
||||
return "This Track"
|
||||
elif value == 1:
|
||||
return "Next Track"
|
||||
return f"{value} Tracks"
|
||||
|
||||
def format_volume(self, scale, value):
|
||||
return f"{int(value*100)}%"
|
||||
|
||||
def get_volume(self):
|
||||
return self.volume.get_value()
|
||||
|
||||
def on_counter_changed(self, scale):
|
||||
value = int(scale.get_value())
|
||||
icon = "pause" if value > -1 else "start"
|
||||
text = " " if value == -1 else value
|
||||
self.pause.set_from_icon_name(f"media-playback-{icon}")
|
||||
self.count.set_markup(f"<small>{text}</small>")
|
||||
|
||||
def on_volume_changed(self, scale):
|
||||
value = scale.get_value()
|
||||
settings.set("audio.volume", value)
|
||||
if value == 0:
|
||||
self.vol_img.set_from_icon_name("audio-volume-muted-symbolic")
|
||||
elif value < 1/3:
|
||||
self.vol_img.set_from_icon_name("audio-volume-low-symbolic")
|
||||
elif value < 2/3:
|
||||
self.vol_img.set_from_icon_name("audio-volume-medium-symbolic")
|
||||
else:
|
||||
self.vol_img.set_from_icon_name("audio-volume-high-symbolic")
|
|
@ -1,5 +1,6 @@
|
|||
# Copyright 2021 (c) Anna Schumaker.
|
||||
from . import artwork
|
||||
from . import scale
|
||||
from . import controls
|
||||
from lib import publisher
|
||||
from lib import settings
|
||||
|
@ -13,6 +14,7 @@ class Player(GObject.GObject):
|
|||
self.video = Gst.ElementFactory.make("fakesink")
|
||||
self.playbin = Gst.ElementFactory.make("playbin")
|
||||
self.playbin.set_property("video-sink", self.video)
|
||||
self.Autopause = scale.AutoPauseScale()
|
||||
|
||||
self.bus = self.playbin.get_bus()
|
||||
self.bus.add_signal_watch()
|
||||
|
@ -20,20 +22,12 @@ class Player(GObject.GObject):
|
|||
self.bus.connect("message::state-changed", self.on_state_changed)
|
||||
self.bus.connect("message::tag", self.on_tag)
|
||||
|
||||
self.Controls = controls.Controls()
|
||||
self.Controls.connect("previous", self.previous)
|
||||
self.Controls.connect("play", self.play)
|
||||
self.Controls.connect("pause", self.pause)
|
||||
self.Controls.connect("next", self.next)
|
||||
self.Controls.connect("volume-changed", self.volume_changed)
|
||||
|
||||
self.Artwork = artwork.Artwork()
|
||||
|
||||
self.track = tagdb.Tracks[settings.get_int("audio.trackid")]
|
||||
self.load_set_state(self.track, Gst.State.PAUSED)
|
||||
if self.track:
|
||||
self.track.add_to_playlist("Previous")
|
||||
self.volume_changed()
|
||||
|
||||
def duration(self):
|
||||
(res, dur) = self.playbin.query_duration(Gst.Format.TIME)
|
||||
|
@ -45,6 +39,9 @@ class Player(GObject.GObject):
|
|||
return state
|
||||
return ret
|
||||
|
||||
def get_volume(self):
|
||||
return self.playbin.get_property("volume")
|
||||
|
||||
def load_track(self, track):
|
||||
prev = self.track
|
||||
self.track = track
|
||||
|
@ -71,7 +68,6 @@ class Player(GObject.GObject):
|
|||
|
||||
def on_state_changed(self, bus, message):
|
||||
(old, new, pending) = message.parse_state_changed()
|
||||
self.Controls.set_state(new)
|
||||
self.emit("state-changed", old, new, pending)
|
||||
|
||||
def on_tag(self, bus, message):
|
||||
|
@ -115,8 +111,8 @@ class Player(GObject.GObject):
|
|||
def seek(self, value):
|
||||
self.playbin.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, value)
|
||||
|
||||
def volume_changed(self, *args):
|
||||
self.playbin.set_property("volume", self.Controls.menu.volume.get_value())
|
||||
def set_volume(self, volume):
|
||||
self.playbin.set_property("volume", volume)
|
||||
|
||||
@GObject.Signal(arg_types=(Gst.State, Gst.State, Gst.State))
|
||||
def state_changed(self, old, new, pending):
|
||||
|
|
|
@ -186,47 +186,3 @@ class TestAudioControls(unittest.TestCase):
|
|||
self.assertIsInstance(child, controls.NextButton)
|
||||
child = child.get_next_sibling()
|
||||
self.assertIsInstance(child, controls.MenuButton)
|
||||
|
||||
|
||||
class TestControls(unittest.TestCase):
|
||||
def test_controls_init(self):
|
||||
ctrl = controls.Controls()
|
||||
|
||||
self.assertIsInstance(ctrl, Gtk.Box)
|
||||
self.assertIsInstance(ctrl.previous, Gtk.Button)
|
||||
self.assertIsInstance(ctrl.play, Gtk.Button)
|
||||
self.assertIsInstance(ctrl.pause, Gtk.Button)
|
||||
self.assertIsInstance(ctrl.next, Gtk.Button)
|
||||
self.assertIsInstance(ctrl.menu, Gtk.MenuButton)
|
||||
self.assertIsInstance(ctrl.sizegroup, Gtk.SizeGroup)
|
||||
|
||||
self.assertEqual(ctrl.get_orientation(), Gtk.Orientation.HORIZONTAL)
|
||||
self.assertEqual(ctrl.previous.get_icon_name(), "media-skip-backward")
|
||||
self.assertEqual(ctrl.play.get_icon_name(), "media-playback-start")
|
||||
self.assertEqual(ctrl.pause.get_icon_name(), "media-playback-pause")
|
||||
self.assertEqual(ctrl.next.get_icon_name(), "media-skip-forward")
|
||||
|
||||
self.assertTrue(ctrl.has_css_class("linked"))
|
||||
self.assertTrue(ctrl.has_css_class("large-icons"))
|
||||
self.assertTrue(ctrl.menu.has_css_class("normal-icons"))
|
||||
self.assertFalse(ctrl.pause.is_visible())
|
||||
|
||||
self.assertIn(ctrl.previous, ctrl)
|
||||
self.assertIn(ctrl.play, ctrl)
|
||||
self.assertIn(ctrl.pause, ctrl)
|
||||
self.assertIn(ctrl.next, ctrl)
|
||||
self.assertIn(ctrl.menu, ctrl)
|
||||
self.assertIn(ctrl, ctrl.sizegroup.get_widgets())
|
||||
|
||||
def test_controls_state(self):
|
||||
ctrl = controls.Controls()
|
||||
self.assertTrue(ctrl.play.is_visible())
|
||||
self.assertFalse(ctrl.pause.is_visible())
|
||||
|
||||
ctrl.set_state(Gst.State.PLAYING)
|
||||
self.assertFalse(ctrl.play.is_visible())
|
||||
self.assertTrue(ctrl.pause.is_visible())
|
||||
|
||||
ctrl.set_state(Gst.State.READY)
|
||||
self.assertTrue(ctrl.play.is_visible())
|
||||
self.assertFalse(ctrl.pause.is_visible())
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
# Copyright 2021 (c) Anna Schumaker.
|
||||
from . import menu
|
||||
from lib import settings
|
||||
from gi.repository import Gtk
|
||||
import tagdb
|
||||
import unittest
|
||||
|
||||
class TestAudioMenu(unittest.TestCase):
|
||||
def setUp(self):
|
||||
settings.reset()
|
||||
|
||||
def test_audio_menu_init(self):
|
||||
button = menu.Button()
|
||||
|
||||
self.assertIsInstance(button, Gtk.MenuButton)
|
||||
self.assertIsInstance(button.popover, Gtk.Popover)
|
||||
self.assertIsInstance(button.overlay, Gtk.Overlay)
|
||||
self.assertIsInstance(button.toggle, Gtk.ToggleButton)
|
||||
self.assertIsInstance(button.grid, Gtk.Grid)
|
||||
self.assertIsNotNone(button.icon)
|
||||
|
||||
self.assertTrue(button.has_css_class("normal-icons"))
|
||||
self.assertTrue(button.grid.has_css_class("large-icons"))
|
||||
|
||||
self.assertEqual(button.grid.get_column_spacing(), 5)
|
||||
self.assertEqual(button.get_popover(), button.popover)
|
||||
self.assertEqual(button.popover.get_child(), button.grid)
|
||||
self.assertEqual(button.toggle, button.get_first_child())
|
||||
self.assertEqual(button.toggle.get_child(), button.overlay)
|
||||
self.assertEqual(button.icon.get_margin_top(), 5)
|
||||
|
||||
self.assertIn(button.icon, button.overlay)
|
||||
|
||||
def test_audio_menu_counter_init(self):
|
||||
button = menu.Button()
|
||||
|
||||
self.assertIsInstance(button.pause, Gtk.Image)
|
||||
self.assertIsInstance(button.count, Gtk.Label)
|
||||
self.assertIsInstance(button.counter, Gtk.Range)
|
||||
|
||||
self.assertEqual(button.pause.get_icon_name(), "media-playback-start")
|
||||
self.assertEqual(button.count.get_text(), " ")
|
||||
self.assertEqual(button.count.get_yalign(), 0)
|
||||
self.assertEqual(button.counter.get_adjustment(), tagdb.Stack.Counter)
|
||||
self.assertEqual(button.counter.get_digits(), 0)
|
||||
self.assertTrue(button.counter.get_draw_value())
|
||||
|
||||
self.assertIn(button.pause, button.grid)
|
||||
self.assertIn(button.counter, button.grid)
|
||||
self.assertIn(button.count, button.overlay)
|
||||
|
||||
def test_audio_menu_counter(self):
|
||||
button = menu.Button()
|
||||
|
||||
self.assertEqual(button.format_counter(button.counter, -1), "Keep Playing")
|
||||
self.assertEqual(button.format_counter(button.counter, 0), "This Track")
|
||||
self.assertEqual(button.format_counter(button.counter, 1), "Next Track")
|
||||
self.assertEqual(button.format_counter(button.counter, 2), "2 Tracks")
|
||||
|
||||
tagdb.Stack.Counter.increment()
|
||||
self.assertEqual(button.pause.get_icon_name(), "media-playback-pause")
|
||||
self.assertEqual(button.count.get_text(), "0")
|
||||
|
||||
tagdb.Stack.Counter.decrement()
|
||||
self.assertEqual(button.pause.get_icon_name(), "media-playback-start")
|
||||
self.assertEqual(button.count.get_text(), " ")
|
||||
|
||||
def test_audio_menu_volume_init(self):
|
||||
button = menu.Button()
|
||||
adjustment = button.volume.get_adjustment()
|
||||
|
||||
self.assertIsInstance(button.vol_img, Gtk.Image)
|
||||
self.assertIsInstance(button.volume, Gtk.Scale)
|
||||
|
||||
self.assertTrue(button.volume.get_draw_value())
|
||||
|
||||
self.assertEqual(settings.get_float("audio.volume"), 1.0)
|
||||
self.assertEqual(adjustment.get_lower(), 0.0)
|
||||
self.assertEqual(adjustment.get_upper(), 1.0)
|
||||
self.assertEqual(adjustment.get_step_increment(), 0.05)
|
||||
self.assertEqual(adjustment.get_value(), 1.0)
|
||||
self.assertEqual(button.vol_img.get_icon_name(), "audio-volume-high-symbolic")
|
||||
|
||||
self.assertIn(button.vol_img, button.grid)
|
||||
self.assertIn(button.volume, button.grid)
|
||||
|
||||
def test_audio_menu_volume(self):
|
||||
button = menu.Button()
|
||||
|
||||
button.volume.set_value(0)
|
||||
self.assertEqual(button.vol_img.get_icon_name(), "audio-volume-muted-symbolic")
|
||||
self.assertEqual(settings.get("audio.volume"), "0.0")
|
||||
self.assertEqual(button.get_volume(), 0.0)
|
||||
|
||||
button.volume.set_value(0.3)
|
||||
self.assertEqual(button.vol_img.get_icon_name(), "audio-volume-low-symbolic")
|
||||
self.assertEqual(settings.get("audio.volume"), "0.3")
|
||||
self.assertEqual(button.get_volume(), 0.3)
|
||||
|
||||
button.volume.set_value(0.6)
|
||||
self.assertEqual(button.vol_img.get_icon_name(), "audio-volume-medium-symbolic")
|
||||
self.assertEqual(settings.get("audio.volume"), "0.6")
|
||||
self.assertEqual(button.get_volume(), 0.6)
|
||||
|
||||
button.volume.set_value(0.9)
|
||||
self.assertEqual(button.vol_img.get_icon_name(), "audio-volume-high-symbolic")
|
||||
self.assertEqual(settings.get("audio.volume"), "0.9")
|
||||
self.assertEqual(button.get_volume(), 0.9)
|
|
@ -3,6 +3,7 @@ from . import artwork
|
|||
from . import controls
|
||||
from . import nowplaying
|
||||
from . import player
|
||||
from . import scale
|
||||
from lib import publisher
|
||||
from lib import settings
|
||||
from gi.repository import GObject
|
||||
|
@ -45,8 +46,8 @@ class TestPlayer(unittest.TestCase):
|
|||
self.assertIsInstance(play.video, Gst.Element)
|
||||
self.assertIsInstance(play.playbin, Gst.Element)
|
||||
self.assertIsInstance(play.bus, Gst.Bus)
|
||||
self.assertIsInstance(play.Controls, controls.Controls)
|
||||
self.assertIsInstance(play.Artwork, artwork.Artwork)
|
||||
self.assertIsInstance(play.Autopause, scale.AutoPauseScale)
|
||||
self.assertIsNone(play.track)
|
||||
|
||||
self.assertEqual(play.playbin.get_property("video-sink"), play.video)
|
||||
|
|
|
@ -3,7 +3,10 @@ from gi.repository import Gtk
|
|||
import audio
|
||||
|
||||
Header = Gtk.HeaderBar()
|
||||
Header.pack_start(audio.Player.Controls)
|
||||
|
||||
controls = audio.AudioControls()
|
||||
Header.pack_start(controls)
|
||||
|
||||
Header.set_title_widget(audio.NowPlaying())
|
||||
|
||||
seekctrl = audio.SeekControl()
|
||||
|
|
|
@ -7,6 +7,7 @@ from . import header
|
|||
class TestHeader(unittest.TestCase):
|
||||
def test_header_init(self):
|
||||
self.assertIsInstance(header.Header, Gtk.HeaderBar)
|
||||
self.assertIsInstance(header.controls, audio.controls.AudioControls)
|
||||
self.assertIsInstance(header.Header.get_title_widget(),
|
||||
audio.nowplaying.NowPlaying)
|
||||
self.assertIsInstance(header.seekctrl, audio.scale.ScaleButtonBox)
|
||||
|
|
Loading…
Reference in New Issue