This begins to implement the MediaPlayer2.Player interface. The
properties and signals are there, and I expect to fully implement them
as Emmental development goes on.
Implements: #7 ("Add MPRIS2 Support")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This includes a set of Gtk.CheckButtons to choose what ReplayGain mode
to use, and a Gtk.Switch to enable or disable ReplayGain
Implements: #46 ("Create new Volume controls")
Implements: #48 ("Implement Intelligent ReplayGain")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
They live in a Gtk.MenuButton with a custom popover box that can have
replaygain options added to it. I also modify the Application to save
the volume when it is changed.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I can't use a Gtk.VolumeButton because I want to add ReplayGain controls
under the popover menu as well.
Implements: #46 ("Create new Volume controls")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This dialog is used to manually edit the settings in the database. I
bind the properties in such a way that changes are seen instantly.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The header currently contains just the title & subtitle information, but
will be expanded to add volume controls in the next patch.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The LabelRow is an implementation of the ListRow for the common case of
displaying text to the user. It has some convenience properties for
setting the xalign property and adding the "numeric" class to the Gtk.Label.
The LabelFactory creates LabelRows.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The ListRow class is intended to be used as a base class for displaying
individual Gtk.ListView rows. The implement some helpful functionality
to make it easier to bind list items to child widgets.
The Factory class is designed to create ListRow widgets.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I implement Integer, Float, and String entries that update their "value"
property based on the user-provided text when the Enter key is pressed.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This entry provides some helper functionality around a Gtk.SearchEntry
to make filtering lists easier.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This takes the input string, casefolds it, and then adds some extra glob
operators to it so we can do a case insensitive substring search by
default.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is a MenuButton that already has a popover attached and a property
for setting the popover child directly.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Bind the width and height properties to the settings so they are
restored on startup and bind the fullscreen property to mpris.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This window is set up with specific areas for our header, sidebar, now
playing info, and tracklist. It also implements a post_toast() function
so toast notifications can be displayed to the user.
Implements: #44 ("Create a new 3WayPane widget")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This creates a new class to dynamically create GObject Properties, save
them to the database, and make it easy to bind application properties to
specific settings properties.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is a Gtk.FilterListModel containing a store.SortedList to store
individual rows in sorted order. I also implemented some convenience
functions to make it easier to add, remove, look up, and filter rows.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This filter takes a set of primary keys for rows that should be visible
during filtering. Passing None as a value means that all rows are shown.
It also has functions for adding or removing individual rows from the
filter.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This will be shared between settings, playlists, and tracks so we have a
common interface for working with database rows.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This inherits from the base Connection manager and adds in reading our
sql script to set up the database. It will also eventually hold pointers
to table objects that we can access directly.
Finally, I add a db property to the Application instance. The db is
connected during the ::startup signal handler, and disconnected during
the ::shutdown signal handler.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is a wrapper around the sqlite3.Connection objct that adds some
nice functionality to make working with SQL easier.
I defined the following magic methods:
* __enter__() to manually begin a transaction
* __exit__() to commit or rollback a manual transaction
* __call__() to execute a SQL statement with either positional or
keyword arguments.
Additionally:
* I define a "CASEFOLD" function that can be used in queries
to lowercase unicode text when searching.
* I set foreign_keys = ON so foreign keys checking is always enabled
* I provide an executemany() function for running running the same
statement multiple times with different arguments.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is implemented as an alternative to the Gio.ListStore that uses a
Python list object to hold items.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We can put all our icons into a single resource bundle that gets loaded
and only exists for our app.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I'm going to put all of the main source code into a single subdirectory
under emmental/ and separate out tests into a separate tests/ directory.
Additionally, I have switched over to pytest for running tests to give
me better output (with color!)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
In this case, the call to get_track_index() returns None which can't be
used for the comparisons we're doing. Make sure we handle the None
result explicitely.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We were scheduling the CheckTask, but not following up with a
DirectoryTask to scan for new files. I use this function during the
Gtk.Application startup to automatically update the libraries.
Implements #31 (Automatically update the database during startup)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We don't use this during testing, so put it here instead of in a
submodule.
Implements #26 (Move the EmmentalApplication into emmental.py)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is cleaner than needing to set an environment variable before
running unit tests.
Implements #28 (Check if unittest is loaded to determine if we are testing)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>