sidebar: Remove old Sidebar code

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2021-10-13 13:13:57 -04:00
parent 35e31d0553
commit 281fda1933
12 changed files with 3 additions and 982 deletions

View File

@ -1,13 +1,6 @@
# Copyright 2021 (c) Anna Schumaker.
from . import library
from . import pulser
from . import stack
from . import tagbox
from . import user
from lib import settings
from gi.repository import Gtk
import audio
import tagdb
from . import stack
class Sidebar(Gtk.Box):
def __init__(self):
@ -15,60 +8,3 @@ class Sidebar(Gtk.Box):
switcher = stack.Switcher()
self.append(switcher)
self.append(stack.Box(switcher.get_stack()))
Switcher = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
Stack = Gtk.Stack()
Box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
#
# Add pages to the Stack and set up the switcher toggles
#
Toggles = [ ]
Switcher.add_css_class("osd")
Switcher.add_css_class("linked")
Switcher.add_css_class("large-icons")
Stack.set_transition_type(Gtk.StackTransitionType.OVER_UP_DOWN)
def initialize():
settings.initialize("sidebar.page", "Libraries")
initialize()
def switch_page(toggle):
if toggle.get_active():
Stack.set_visible_child_name(toggle.get_name())
settings.set("sidebar.page", toggle.get_name())
def on_tag_push_pop(old, new):
old.widgets.set_label()
new.widgets.set_label()
tagdb.Stack.PushPop.register(on_tag_push_pop)
def add_stack_page(name, page):
toggle = Gtk.ToggleButton()
toggle.set_icon_name(page.icon)
toggle.set_vexpand(True)
toggle.set_name(name)
toggle.connect("toggled", switch_page)
if len(Toggles) > 0:
toggle.set_group(Toggles[0])
Toggles.append(toggle)
Switcher.append(toggle)
Stack.add_named(page, name)
toggle.set_active(settings.get("sidebar.page") == name)
add_stack_page("Playlists", user.TagBox)
add_stack_page("Artists", tagbox.ParentTagBox(tagdb.tags.Artist, "avatar-default-symbolic",
tagdb.tags.Album, "media-optical", header=True))
add_stack_page("Genres", tagbox.TagBox(tagdb.tags.Genre, "emblem-generic", header=True))
add_stack_page("Decades", tagbox.ParentTagBox(tagdb.tags.Decade, "x-office-calendar",
tagdb.tags.Year, "x-office-calendar-symbolic"))
add_stack_page("Libraries", library.Box)
Box.append(audio.Artwork())
Box.append(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL))
Box.append(Stack)
Box.append(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL))
Box.append(pulser.Box)

View File

@ -1,84 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from . import tagbox
from . import tagrow
from gi.repository import Gtk
import pathlib
import tagdb
class LibraryTagRow(tagrow.TagRow):
def __init__(self, tag, icon):
super().__init__(tag, icon)
self.update = Gtk.Button.new_from_icon_name("view-refresh")
self.update.set_hexpand(True)
self.update.connect("clicked", self.update_clicked)
self.remove = Gtk.Button.new_from_icon_name("list-remove")
self.remove.set_hexpand(True)
self.remove.connect("clicked", self.remove_clicked)
self.box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
self.box.add_css_class("linked")
self.box.append(self.update)
self.box.append(self.remove)
self.grid.attach(self.box, 0, 1, 2, 1)
def update_clicked(self, button):
self.tag.scan()
def remove_clicked(self, button):
tagdb.Library.remove(self.tag)
class LibraryTagBox(tagbox.TagBox):
def __alloc_tagrow__(self, tag):
return LibraryTagRow(tag, self.icon)
TagBox = LibraryTagBox(tagdb.Library, "folder-music")
#
# Configure the directory chooser popover and menu button
#
DirFilter = Gtk.FileFilter()
DirFilter.add_mime_type("inode/directory")
DirChooser = Gtk.FileChooserWidget()
DirChooser.set_action(Gtk.FileChooserAction.SELECT_FOLDER)
DirChooser.set_create_folders(False)
DirChooser.set_filter(DirFilter)
def selected_path():
if (file := DirChooser.get_file()) == None:
file = DirChooser.get_current_folder()
return pathlib.Path(file.get_path())
def on_select(button):
if (path := selected_path()) != None:
tagdb.Library.add(path).scan()
Popover.popdown()
DirSelect = Gtk.Button.new_with_label("Select Folder")
DirSelect.add_css_class("suggested-action")
DirSelect.connect("clicked", on_select)
DirBox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
DirBox.append(DirChooser)
DirBox.append(DirSelect)
Popover = Gtk.Popover()
Popover.add_css_class("normal-icons")
Popover.set_child(DirBox)
Add = Gtk.MenuButton()
Add.add_css_class("large-icons")
Add.set_icon_name("folder-new")
Add.set_direction(Gtk.ArrowType.UP)
Add.set_popover(Popover)
Box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
Box.add_css_class("linked")
Box.set_hexpand(True)
Box.append(TagBox)
Box.append(Add)
Box.icon = TagBox.icon

View File

@ -1,53 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from gi.repository import Gtk, GLib
import lib
import threading
Bar = Gtk.ProgressBar()
Threads = [ ]
Lock = threading.Lock()
Timeout = None
Bar.hide()
Bar.set_valign(Gtk.Align.CENTER)
Bar.set_hexpand(True)
Box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
Box.append(Gtk.Label.new(str=" "))
Box.append(Bar)
Box.append(Gtk.Label.new(str=" "))
def do_pulses():
global Timeout
Bar.pulse()
with Lock:
if not Threads[0].running():
Threads.pop(0)
if len(Threads) == 0:
Timeout = None
Bar.hide()
return GLib.SOURCE_REMOVE
return GLib.SOURCE_CONTINUE
def start_pulsing(thread):
global Timeout
with Lock:
Threads.append(thread)
if Timeout == None:
Timeout = GLib.timeout_add(100, do_pulses)
Bar.show()
def initialize():
lib.thread.Start.register(start_pulsing)
lib.bus.Start.register(start_pulsing)
initialize()
def reset():
global Timeout
with Lock:
Threads.clear()
if Timeout != None:
GLib.source_remove(Timeout)
Timeout = None
Bar.hide()

View File

@ -1,126 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from . import tagrow
from gi.repository import Gtk
import lib
import playlist
import tagdb
class TagBox(Gtk.ScrolledWindow):
def __init__(self, tagstore, icon, header=False):
Gtk.ScrolledWindow.__init__(self)
self.listbox = Gtk.ListBox()
self.tagstore = tagstore
self.icon = icon
self.bus = lib.bus.Bus(50)
self.set_child(self.listbox)
self.set_vexpand(True)
for tag in self.tagstore.tags():
self.on_tag_added(tag)
self.listbox.set_activate_on_single_click(False)
self.listbox.set_sort_func(self.sort_func)
if header == True:
self.listbox.set_header_func(self.header_func)
self.listbox.connect("row-activated", self.row_activated)
self.listbox.connect("row-selected", self.row_selected)
tagstore.Added.register(self.tag_added)
tagstore.Removed.register(self.tag_removed)
def __alloc_tagrow__(self, tag):
return tagrow.TagRow(tag, self.icon)
def __getitem__(self, i):
return self.listbox.get_row_at_index(i)
def clear(self):
while (row := self[0]) != None:
self.on_tag_removed(row.tag)
self.bus.clear()
def header_func(self, cur, prev):
c = cur.tag.get_header()
if prev == None or prev.tag.get_header() != c:
cur.set_header(tagrow.TagHeader(c))
else:
cur.set_header(None)
def row_activated(self, listbox, row):
tagdb.Stack.push(row.tag)
def row_selected(self, listbox, row):
playlist.Model.switch_tag(row.tag)
def sort_func(self, lhs, rhs):
if lhs.tag < rhs.tag:
return -1
if rhs.tag < lhs.tag:
return 1
return 0
def on_tag_added(self, tag):
tag.widgets = self.__alloc_tagrow__(tag)
tag.TrackAdded.register(self.tag_changed)
tag.TrackRemoved.register(self.tag_changed)
self.listbox.append(tag.widgets)
def tag_added(self, tag):
self.bus.board(self.on_tag_added, tag)
def on_tag_changed(self, tag):
tag.widgets.set_label()
def tag_changed(self, tag, track, pos):
self.bus.board(self.on_tag_changed, tag)
def on_tag_removed(self, tag):
self.listbox.remove(tag.widgets)
tag.TrackAdded.unregister(self.tag_changed)
tag.TrackRemoved.unregister(self.tag_changed)
tag.widgets = None
def tag_removed(self, tag):
self.bus.board(self.on_tag_removed, tag)
class ParentTagBox(TagBox):
def __init__(self, tagstore, icon, childstore, childicon, header=False):
TagBox.__init__(self, tagstore, icon, header)
self.childstore = childstore
self.childicon = childicon
for child in childstore.tags():
self.on_child_tag_added(child)
childstore.Added.register(self.child_tag_added)
childstore.Removed.register(self.child_tag_removed)
def __alloc_tagrow__(self, tag):
return tagrow.ParentTagRow(tag, self.icon)
def on_child_tag_added(self, tag):
tag.widgets = tagrow.TagRow(tag, self.childicon)
tag.widgets.set_margin_start(35)
tag.parent.widgets.add_child(tag.widgets)
tag.TrackAdded.register(self.tag_changed)
tag.TrackRemoved.register(self.tag_changed)
self.listbox.append(tag.widgets)
def child_tag_added(self, tag):
self.bus.board(self.on_child_tag_added, tag)
def on_child_tag_removed(self, tag):
self.listbox.remove(tag.widgets)
tag.TrackAdded.unregister(self.tag_changed)
tag.TrackRemoved.unregister(self.tag_changed)
tag.widgets = None
def child_tag_removed(self, tag):
self.bus.board(self.on_child_tag_removed, tag)
def header_func(self, cur, prev):
if isinstance(cur, tagrow.ParentTagRow):
if prev and not isinstance(prev, tagrow.ParentTagRow):
prev = prev.tag.parent.widgets
super().header_func(cur, prev)

View File

@ -1,67 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from gi.repository import Gtk, GLib, Pango
import tagdb
class TagRow(Gtk.ListBoxRow):
def __init__(self, tag, icon):
Gtk.ListBoxRow.__init__(self)
self.tag = tag
self.grid = Gtk.Grid()
self.image = Gtk.Image.new_from_icon_name(icon)
self.image.set_margin_start(5)
self.image.set_margin_end(5)
self.label = Gtk.Label()
self.label.set_halign(Gtk.Align.START)
self.label.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
self.label.set_hexpand(True)
self.grid.attach(self.image, 0, 0, 1, 1)
self.grid.attach(self.label, 1, 0, 1, 1)
self.grid.set_margin_end(5)
self.set_child(self.grid)
self.set_label()
def set_label(self):
count = len(self.tag)
bold = tagdb.Stack.current() == self.tag
text = f"{self.tag.name}\n{count} Track{'s' if count != 1 else ''}"
self.label.set_markup(("<b>%s</b>" if bold else "%s") %
GLib.markup_escape_text(text))
class ParentTagRow(TagRow):
def __init__(self, tag, icon):
TagRow.__init__(self, tag, icon)
self.children = [ ]
self.expander = Gtk.ToggleButton()
self.expander.connect("toggled", self.on_toggle)
self.expander.set_icon_name("pan-end-symbolic")
self.expander.add_css_class("flat")
self.grid.insert_column(0)
self.grid.attach(self.expander, 0, 0, 1, 1)
def add_child(self, child):
self.children.append(child)
child.set_visible(self.expander.get_active())
def on_toggle(self, button):
direction = "down" if self.expander.get_active() else "end"
self.expander.set_icon_name(f"pan-{direction}-symbolic")
for child in self.children:
child.set_visible(self.expander.get_active())
class TagHeader(Gtk.Box):
def __init__(self, char):
Gtk.Box.__init__(self)
self.set_orientation(Gtk.Orientation.VERTICAL)
self.set_margin_top(5)
self.label = Gtk.Label()
self.label.set_markup(f"<small><b>{char}</b></small>")
self.separator = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)
self.append(self.label)
self.append(self.separator)

View File

@ -1,99 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from . import library
from . import tagbox
from gi.repository import Gtk, Gio, GLib
import pathlib
import tagdb
import unittest
main_context = GLib.main_context_default()
test_library = pathlib.Path("./data/Test Library").absolute()
test_artist1 = test_library / "Test Artist 01"
class TestLibrarySidebar(unittest.TestCase):
def tearDown(self):
tagdb.reset()
library.TagBox.clear()
def test_library_sidebar_init(self):
self.assertIsInstance(library.TagBox, library.LibraryTagBox)
self.assertIsInstance(library.TagBox, tagbox.TagBox)
self.assertIsInstance(library.Add, Gtk.MenuButton)
self.assertIsInstance(library.Box, Gtk.Box)
self.assertTrue(library.Box.has_css_class("linked"))
self.assertTrue(library.Box.get_hexpand())
self.assertIn(library.TagBox, library.Box)
self.assertIn(library.Add, library.Box)
def test_library_sidebar_row(self):
library.TagBox = library.LibraryTagBox(tagdb.Library, "folder-music")
lib_tag = tagdb.Library.add(test_artist1)
lib_tag.scan().join()
library.TagBox.bus.complete()
row = lib_tag.widgets
self.assertIsInstance(row, library.LibraryTagRow)
self.assertIsInstance(row.update, Gtk.Button)
self.assertIsInstance(row.remove, Gtk.Button)
self.assertIsInstance(row.box, Gtk.Box)
self.assertTrue(row.update.get_hexpand())
self.assertTrue(row.remove.get_hexpand())
self.assertTrue(row.box.has_css_class("linked"))
self.assertIn(row.box, row.grid)
self.assertIn(row.update, row.box)
self.assertIn(row.remove, row.box)
row.update_clicked(row.update)
lib_tag.scan.join()
row.remove_clicked(row.remove)
lib_tag.clear.join()
library.TagBox.bus.complete()
self.assertIsNone(library.TagBox[0])
def test_library_sidebar_add(self):
self.assertIsInstance(library.Popover, Gtk.Popover)
self.assertTrue(library.Popover.has_css_class("normal-icons"))
self.assertEqual(library.Add.get_icon_name(), "folder-new")
self.assertEqual(library.Add.get_direction(), Gtk.ArrowType.UP)
self.assertTrue(library.Add.has_css_class("large-icons"))
self.assertEqual(library.Add.get_popover(), library.Popover)
self.assertEqual(library.Popover.get_child(), library.DirBox)
def test_library_sidebar_dir_chooser(self):
self.assertIsInstance(library.DirFilter, Gtk.FileFilter)
self.assertIsInstance(library.DirChooser, Gtk.FileChooserWidget)
self.assertIsInstance(library.DirSelect, Gtk.Button)
self.assertIsInstance(library.DirBox, Gtk.Box)
self.assertEqual(library.DirChooser.get_filter(), library.DirFilter)
self.assertEqual(library.DirChooser.get_action(),
Gtk.FileChooserAction.SELECT_FOLDER)
self.assertFalse(library.DirChooser.get_create_folders())
self.assertIn(library.DirChooser, library.DirBox)
self.assertEqual(library.DirSelect.get_label(), "Select Folder")
self.assertTrue(library.DirSelect.has_css_class("suggested-action"))
self.assertIn(library.DirSelect, library.DirBox)
#library.Popover.popup()
gfile = Gio.File.new_for_path(str(test_library))
self.assertTrue(library.DirChooser.set_current_folder(gfile))
while main_context.iteration(may_block=False): pass
self.assertEqual(library.selected_path(), test_library)
gfile = Gio.File.new_for_path(str(test_artist1))
self.assertTrue(library.DirChooser.set_file(gfile))
while main_context.iteration(may_block=False): pass
self.assertEqual(library.selected_path(), test_artist1)
library.on_select(library.DirSelect)
self.assertFalse(library.Popover.is_visible())
self.assertIn(test_artist1, tagdb.Library.store)
tagdb.Library[test_artist1].scan.join()

View File

@ -1,55 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from . import pulser
from gi.repository import Gtk, GLib
import lib
import threading
import unittest
class TestThread:
def __init__(self): pass
def running(self): return False
class TestUIPulser(unittest.TestCase):
def setUp(self):
pulser.reset()
pulser.initialize()
pulser.reset()
def test_pulser_init(self):
self.assertIsInstance(pulser.Bar, Gtk.ProgressBar)
self.assertIsInstance(pulser.Box, Gtk.Box)
self.assertIsInstance(pulser.Lock, type(threading.Lock()))
self.assertIsNone(pulser.Timeout)
self.assertTrue(pulser.Bar.get_hexpand())
self.assertFalse(pulser.Bar.get_visible())
self.assertEqual(pulser.Threads, [ ])
self.assertEqual(pulser.Bar.get_valign(), Gtk.Align.CENTER)
self.assertIn(pulser.Bar, pulser.Box)
self.assertIn(pulser.start_pulsing, lib.thread.Start.subscribers)
self.assertIn(pulser.start_pulsing, lib.bus.Start.subscribers)
def test_pulser_pulse(self):
t1 = TestThread()
t2 = TestThread()
pulser.start_pulsing(t1)
self.assertEqual(pulser.Threads, [ t1 ])
tid = pulser.Timeout
self.assertIsNotNone(tid)
self.assertTrue(pulser.Bar.get_visible())
pulser.start_pulsing(t2)
self.assertEqual(pulser.Threads, [ t1, t2 ])
self.assertEqual(pulser.Timeout, tid)
pulser.do_pulses()
self.assertEqual(pulser.Threads, [ t2 ])
pulser.do_pulses()
self.assertEqual(pulser.Threads, [ ])
self.assertIsNone(pulser.Timeout)
self.assertFalse(pulser.Bar.get_visible())
GLib.source_remove(tid)

View File

@ -1,10 +1,7 @@
# Copyright 2021 (c) Anna Schumaker.
import audio
import sidebar
import unittest
from lib import settings
from gi.repository import Gtk
from . import stack
class TestSidebar(unittest.TestCase):
def test_init(self):
@ -12,79 +9,6 @@ class TestSidebar(unittest.TestCase):
self.assertIsInstance(sbar, Gtk.Box)
child = sbar.get_first_child()
self.assertIsInstance(child, stack.Switcher)
self.assertIsInstance(child, sidebar.stack.Switcher)
child = child.get_next_sibling()
self.assertIsInstance(child, stack.Box)
class TestOldSidebar(unittest.TestCase):
def setUpClass():
sidebar.initialize()
def test_sidebar_init(self):
self.assertIsInstance(sidebar.Switcher, Gtk.Box)
self.assertIsInstance(sidebar.Stack, Gtk.Stack)
self.assertIsInstance(sidebar.Box, Gtk.Box)
#self.assertIn(audio.Player.Artwork, sidebar.Box)
self.assertIn(sidebar.Stack, sidebar.Box)
self.assertIn(sidebar.pulser.Box, sidebar.Box)
def test_sidebar_pages(self):
self.assertTrue(sidebar.Switcher.has_css_class("osd"))
self.assertTrue(sidebar.Switcher.has_css_class("linked"))
self.assertTrue(sidebar.Switcher.has_css_class("large-icons"))
self.assertEqual(sidebar.Stack.get_transition_type(), Gtk.StackTransitionType.OVER_UP_DOWN)
self.assertEqual(settings.get("sidebar.page"), "Libraries")
self.assertEqual(sidebar.Stack.get_visible_child_name(), "Libraries")
for toggle in sidebar.Toggles:
self.assertIsInstance(toggle, Gtk.ToggleButton)
self.assertIn(toggle, sidebar.Switcher)
self.assertTrue(toggle.get_vexpand())
self.assertIsInstance(sidebar.Stack.get_child_by_name("Playlists"),
sidebar.user.UserTagBox)
self.assertEqual(sidebar.Toggles[0].get_icon_name(), "audio-x-generic")
self.assertEqual(sidebar.Toggles[0].get_name(), "Playlists")
sidebar.Toggles[0].set_active(True)
self.assertEqual(sidebar.Stack.get_visible_child_name(), "Playlists")
self.assertEqual(settings.get("sidebar.page"), "Playlists")
self.assertIsInstance(sidebar.Stack.get_child_by_name("Artists"),
sidebar.tagbox.ParentTagBox)
self.assertEqual(sidebar.Toggles[1].get_icon_name(), "avatar-default-symbolic")
self.assertEqual(sidebar.Toggles[1].get_name(), "Artists")
sidebar.Toggles[1].set_active(True)
self.assertEqual(sidebar.Stack.get_visible_child_name(), "Artists")
self.assertEqual(settings.get("sidebar.page"), "Artists")
self.assertIsInstance(sidebar.Stack.get_child_by_name("Genres"),
sidebar.tagbox.TagBox)
self.assertEqual(sidebar.Toggles[2].get_icon_name(), "emblem-generic")
self.assertEqual(sidebar.Toggles[2].get_name(), "Genres")
sidebar.Toggles[2].set_active(True)
self.assertEqual(sidebar.Stack.get_visible_child_name(), "Genres")
self.assertEqual(settings.get("sidebar.page"), "Genres")
self.assertIsInstance(sidebar.Stack.get_child_by_name("Decades"),
sidebar.tagbox.ParentTagBox)
self.assertEqual(sidebar.Toggles[3].get_icon_name(), "x-office-calendar")
self.assertEqual(sidebar.Toggles[3].get_name(), "Decades")
sidebar.Toggles[3].set_active(True)
self.assertEqual(sidebar.Stack.get_visible_child_name(), "Decades")
self.assertEqual(settings.get("sidebar.page"), "Decades")
self.assertEqual(sidebar.Stack.get_child_by_name("Libraries"),
sidebar.library.Box)
self.assertEqual(sidebar.Toggles[4].get_icon_name(), "folder-music")
self.assertEqual(sidebar.Toggles[4].get_name(), "Libraries")
sidebar.Toggles[4].set_active(True)
self.assertEqual(sidebar.Stack.get_visible_child_name(), "Libraries")
self.assertEqual(settings.get("sidebar.page"), "Libraries")
for toggle in sidebar.Toggles:
if toggle != sidebar.Toggles[-1]:
self.assertFalse(toggle.get_active())
else:
self.assertTrue(toggle.get_active())
self.assertIsInstance(child, sidebar.stack.Box)

View File

@ -1,169 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from . import tagbox
from . import tagrow
from lib import fake
from gi.repository import Gtk
import lib
import unittest
class TestTagBox(unittest.TestCase):
def test_tag_box(self):
store = lib.tagstore.TagStore()
tbox = tagbox.TagBox(store, "image-missing")
self.assertEqual(tbox.tagstore, store)
self.assertEqual(tbox.icon, "image-missing")
self.assertEqual(tbox.bus.timeout, 50)
self.assertIsInstance(tbox, Gtk.ScrolledWindow)
self.assertIsInstance(tbox.listbox, Gtk.ListBox)
self.assertIsInstance(tbox.bus, lib.bus.Bus)
viewport = tbox.get_child()
self.assertIsInstance(viewport, Gtk.Viewport)
self.assertEqual(viewport.get_child(), tbox.listbox)
self.assertTrue(tbox.get_vexpand())
self.assertFalse(tbox.listbox.get_activate_on_single_click())
self.assertIn(tbox.tag_added, store.Added.subscribers)
self.assertIn(tbox.tag_removed, store.Removed.subscribers)
def test_tag_box_add_remove_modify(self):
store = lib.tagstore.TagStore()
tbox = tagbox.TagBox(store, "missing-icon")
tag = store.add("Test", fake.Track(1))
self.assertIn((tbox.on_tag_added, (tag,)), tbox.bus.passengers)
tbox.bus.complete()
self.assertIsInstance(tag.widgets, tagrow.TagRow)
self.assertEqual(tbox[0], tag.widgets)
self.assertIn(tbox.tag_changed, tag.TrackAdded.subscribers)
self.assertEqual(tag.widgets.label.get_text(), "Test\n1 Track")
tag.add_track(fake.Track(2))
self.assertIn((tbox.on_tag_changed, (tag,)), tbox.bus.passengers)
tbox.bus.complete()
self.assertEqual(tag.widgets.label.get_text(), "Test\n2 Tracks")
self.assertIn(tbox.tag_changed, tag.TrackRemoved.subscribers)
tag.remove_track(fake.Track(2))
self.assertIn((tbox.on_tag_changed, (tag,)), tbox.bus.passengers)
tbox.bus.complete()
self.assertEqual(tag.widgets.label.get_text(), "Test\n1 Track")
store.remove(tag)
self.assertIn((tbox.on_tag_removed, (tag,)), tbox.bus.passengers)
tbox.bus.complete()
self.assertIsNone(tag.widgets)
self.assertIsNone(tbox[0])
self.assertNotIn(tbox.tag_changed, tag.TrackAdded.subscribers)
self.assertNotIn(tbox.tag_changed, tag.TrackRemoved.subscribers)
def test_tag_box_clear(self):
store = lib.tagstore.TagStore()
tbox = tagbox.TagBox(store, "missing-icon")
tag1 = store.add("Test1", fake.Track(1))
tag2 = store.add("Test2", fake.Track(1))
tbox.bus.complete()
self.assertEqual(tbox[0].tag, tag1)
self.assertEqual(tbox[1].tag, tag2)
tbox.clear()
self.assertIsNone(tbox[0])
self.assertNotIn(tbox.tag_changed, tag1.TrackAdded.subscribers)
self.assertNotIn(tbox.tag_changed, tag2.TrackAdded.subscribers)
self.assertNotIn(tbox.tag_changed, tag1.TrackRemoved.subscribers)
self.assertNotIn(tbox.tag_changed, tag2.TrackRemoved.subscribers)
def test_tag_box_load(self):
store = lib.tagstore.TagStore()
tag1 = store.add("Test1", fake.Track(1))
tag2 = store.add("Test2", fake.Track(2))
tbox = tagbox.TagBox(store, "missing-icon")
self.assertEqual(tbox[0], tag1.widgets)
self.assertEqual(tbox[1], tag2.widgets)
def test_tag_box_header(self):
store = lib.tagstore.TagStore()
tbox = tagbox.TagBox(store, "missing-icon", header=True)
tagAB = store.add("AB")
tbox.bus.complete()
self.assertIsNotNone(tagAB.widgets.get_header())
tagAA = store.add("AA")
tbox.bus.complete()
self.assertIsNotNone(tagAA.widgets.get_header())
self.assertIsNone(tagAB.widgets.get_header())
def test_tag_box_sort(self):
store = lib.tagstore.TagStore()
tbox = tagbox.TagBox(store, "missing-icon")
tagB = store.add("B", fake.Track(1))
tagA = store.add("A", fake.Track(1))
tagC = store.add("C", fake.Track(1))
tbox.bus.complete()
self.assertEqual(tbox[0].tag, tagA)
self.assertEqual(tbox[1].tag, tagB)
self.assertEqual(tbox[2].tag, tagC)
class TestParentTagBox(unittest.TestCase):
def test_parent_tagbox(self):
store = lib.tagstore.TagStore()
superstore = lib.tagstore.TagSuperStore()
ptbox = tagbox.ParentTagBox(store, "missing-icon",
superstore, "missing-icon")
self.assertIsInstance(ptbox, tagbox.ParentTagBox)
self.assertIsInstance(ptbox, tagbox.TagBox)
self.assertEqual(ptbox.tagstore, store)
self.assertEqual(ptbox.icon, "missing-icon")
self.assertEqual(ptbox.childstore, superstore)
self.assertEqual(ptbox.childicon, "missing-icon")
def test_parent_tagbox_add_remove(self):
store = lib.tagstore.TagStore()
superstore = lib.tagstore.TagSuperStore()
ptbox = tagbox.ParentTagBox(store, "missing-icon",
superstore, "missing-icon")
tag = store.add("Test", fake.Track(1))
ptbox.bus.complete()
self.assertIsInstance(tag.widgets, tagrow.ParentTagRow)
tag1 = superstore.add(tag, "child", fake.Track(1))
ptbox.bus.complete()
self.assertIsInstance(tag1.widgets, tagrow.TagRow)
self.assertEqual(tag1.widgets.get_margin_start(), 35)
superstore.remove(tag1)
ptbox.bus.complete()
self.assertIsNone(tag1.widgets)
store.remove(tag)
ptbox.bus.complete()
self.assertIsNone(tag.widgets)
def test_parent_tagbox_load(self):
store = lib.tagstore.TagStore()
superstore = lib.tagstore.TagSuperStore()
tag = store.add("Test", fake.Track(1))
tag1 = superstore.add(tag, "Tag 1", fake.Track(1))
tag2 = superstore.add(tag, "Tag 2", fake.Track(2))
ptbox = tagbox.ParentTagBox(store, "missing-icon",
superstore, "missing-icon")
self.assertEqual(ptbox[0], tag.widgets)
self.assertEqual(ptbox[1], tag1.widgets)
self.assertEqual(ptbox[2], tag2.widgets)
self.assertIsNone(tag1.widgets.get_header())
self.assertIsNone(tag2.widgets.get_header())

View File

@ -1,99 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from . import tagrow
from gi.repository import Gtk, Pango
import unittest
class FakeTag:
def __init__(self, name):
self.name = name
self.num = 0
def __len__(self):
return self.num
def __lt__(self, rhs):
return self.name < rhs.name
class TestTagRow(unittest.TestCase):
def test_tag_row_init(self):
tag = FakeTag("test")
row = tagrow.TagRow(tag, "missing-icon")
self.assertIsInstance(row, Gtk.ListBoxRow)
self.assertIsInstance(row.grid, Gtk.Grid)
self.assertIsInstance(row.label, Gtk.Label)
self.assertEqual(row.image.get_icon_name(), "missing-icon")
self.assertEqual(row.image.get_margin_start(), 5)
self.assertEqual(row.image.get_margin_end(), 5)
self.assertEqual(row.grid.get_margin_end(), 5)
self.assertEqual(row.label.get_text(), "test\n0 Tracks")
self.assertEqual(row.label.get_halign(), Gtk.Align.START)
self.assertEqual(row.label.get_ellipsize(), Pango.EllipsizeMode.MIDDLE)
self.assertTrue(row.label.get_hexpand())
self.assertIn(row.image, row.grid)
self.assertIn(row.label, row.grid)
self.assertEqual(row.get_child(), row.grid)
def test_tag_row_count(self):
tag = FakeTag("test")
row = tagrow.TagRow(tag, "missing-icon")
tag.num = 1
row.set_label()
self.assertEqual(row.label.get_text(), "test\n1 Track")
tag.num = 4
row.set_label()
self.assertEqual(row.label.get_text(), "test\n4 Tracks")
class TestParentTagRow(unittest.TestCase):
def test_parent_tagrow_init(self):
tag = FakeTag("test")
row = tagrow.ParentTagRow(tag, "missing-icon")
self.assertIsInstance(row, tagrow.TagRow)
self.assertIsInstance(row.expander, Gtk.ToggleButton)
self.assertEqual(row.expander.get_icon_name(), "pan-end-symbolic")
self.assertEqual(row.children, [ ])
self.assertTrue(row.expander.has_css_class("flat"))
self.assertIn(row.expander, row.grid)
def test_parent_tagrow_children(self):
tag = FakeTag("test")
row = tagrow.ParentTagRow(tag, "missing-icon")
c1 = Gtk.Label.new(str="Child 1")
row.add_child(c1)
self.assertEqual(row.children, [ c1 ])
self.assertFalse(c1.is_visible())
row.expander.set_active(True)
self.assertEqual(row.expander.get_icon_name(), "pan-down-symbolic")
self.assertTrue(c1.is_visible())
c2 = Gtk.Label.new(str="Child 2")
row.add_child(c2)
self.assertEqual(row.children, [ c1, c2 ])
row.expander.set_active(False)
self.assertEqual(row.expander.get_icon_name(), "pan-end-symbolic")
self.assertFalse(c1.is_visible())
self.assertFalse(c2.is_visible())
class TestTagHeader(unittest.TestCase):
def test_tag_header(self):
header = tagrow.TagHeader("A")
self.assertIsInstance(header, Gtk.Box)
self.assertIsInstance(header.label, Gtk.Label)
self.assertIsInstance(header.separator, Gtk.Separator)
self.assertEqual(header.label.get_text(), "A")
self.assertEqual(header.get_margin_top(), 5)
self.assertIn(header.label, header)
self.assertIn(header.separator, header)

View File

@ -1,47 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from . import tagbox
from . import tagrow
from . import user
from gi.repository import Gtk
import tagdb
import unittest
Expected = [ ("Collection", "media-playback-start", tagrow.TagRow),
("Favorites", "emmental-favorites", tagrow.TagRow),
("New Tracks", "starred", tagrow.TagRow),
("Previous", "edit-undo", tagrow.TagRow),
("Test", "audio-x-generic", user.UserTagRow),
("Up Next", "edit-redo", tagrow.TagRow) ]
class TestUserSidebar(unittest.TestCase):
def test_user_sidebar_init(self):
self.assertIsInstance(user.TagBox, user.UserTagBox)
self.assertIsInstance(user.TagBox, tagbox.TagBox)
self.assertEqual(user.Icons["Collection"], "media-playback-start")
self.assertEqual(user.Icons["Favorites"], "emmental-favorites")
self.assertEqual(user.Icons["New Tracks"], "starred")
self.assertEqual(user.Icons["Previous"], "edit-undo")
self.assertEqual(user.Icons["Up Next"], "edit-redo")
def test_user_sidebar_row(self):
tag = tagdb.tags.User.add("Test")
row = user.UserTagRow(tag, "audio-x-generic")
self.assertIsInstance(row.remove, Gtk.Button)
self.assertIsInstance(row.KeyEvent, Gtk.EventControllerKey)
self.assertEqual(row.remove.get_icon_name(), "list-remove")
self.assertIn(row.remove, row.grid)
row.remove_tag(row.remove)
self.assertIsNone(tagdb.tags.User["Test"])
def test_user_sidebar(self):
user.TagBox = user.UserTagBox(tagdb.tags.User, "audio-x-generic")
tag = tagdb.tags.User.add("Test")
user.TagBox.bus.complete()
for (i, (tag, icon, type)) in enumerate(Expected):
self.assertIsInstance(user.TagBox[i], type)
self.assertEqual(user.TagBox[i].tag, tagdb.tags.User[tag])
self.assertEqual(user.TagBox[i].image.get_icon_name(), icon)

View File

@ -1,40 +0,0 @@
# Copyright 2021 (c) Anna Schumaker.
from . import tagbox
from . import tagrow
from gi.repository import Gtk, Gdk
import tagdb
Icons = { "Collection" : "media-playback-start",
"Favorites" : "emmental-favorites",
"New Tracks" : "starred",
"Previous" : "edit-undo",
"Up Next" : "edit-redo" }
class UserTagRow(tagrow.TagRow):
def __init__(self, tag, icon):
tagrow.TagRow.__init__(self, tag, icon)
self.remove = Gtk.Button.new_from_icon_name("list-remove")
self.remove.connect("clicked", self.remove_tag)
self.grid.attach(self.remove, 2, 0, 1, 1)
self.KeyEvent = Gtk.EventControllerKey()
self.KeyEvent.connect("key-released", self.on_key_released)
self.add_controller(self.KeyEvent)
def on_key_released(self, controller, keyval, keycode, state):
if Gdk.keyval_name(keyval) == "Delete":
tagdb.tags.User.remove(self.tag)
def remove_tag(self, button):
tagdb.tags.User.remove(self.tag)
class UserTagBox(tagbox.TagBox):
def __alloc_tagrow__(self, tag):
if tag.name not in Icons.keys():
return UserTagRow(tag, self.icon)
return tagrow.TagRow(tag, Icons.get(tag.name, self.icon))
TagBox = UserTagBox(tagdb.tags.User, "audio-x-generic")