I use the current focus widget to set the "user-editing" property, which
can be used to enable or disable accelerator actions.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is inspried by the Gio.ActionEntry struct, which I can't figure out
how to get working in Python. I add on a few extra helpful features,
such as:
- Automatically creating a Gio.SimpleAction
- Tracking the desired accelerator keys
- Binding the "enabled" state to a specificed property at construction
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Otherwise we could lose the changes if the app crashes.
Fixes: #63 ("The database isn't being committed enough")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Otherwise we could have data loss if the application crashes.
Fixes: #63 ("The database isn't being committed enough")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Leaving the database in a dirty state could cause unintentional data
loss if the app crashes.
Fixes: #63 ("The database isn't being committed enough")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This lets us skip a handful of database calls if we detect that we're
setting the active playlist to the same value.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I do this unconditionally, so even if the track is already on the
playlist we set it as active. I think this is what the user would
expect, but I'm open to revising this approach later.
Fixes: #62 ("Queueing tracks doesn't activate the Queued Tracks playlist")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And wire up the bg-enabled and bg-volume properties from the header to
the playbin properties with the same name.
Implements: #50 ("Background Music Mode")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This links together our ReplayGain filter with a volume element that is
set to the user configured background volume when background listening
mode is enabled, and 100% when background listening mode is disabled.
Implements: #50 ("Background Music Mode")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I also update the button tooltip to display the background listening
status along with the current volume level.
Implements: #50 ("Background Music Mode")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And wire up the properties so we can save the user's current setting.
Implements: #50 ("Background Music Mode")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This widget will be added to the Volume popover and allow configuring a
lower volume for background listening while focusing on tasks.
Implements: #50 ("Background Music Mode")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This will be added to a ListBox with the volume controls. Expanding the
row will enable ReplayGain and give the user a menu to select ReplayGain
mode.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The plan is to convert the volume control panel into a Gtk.ListBox for a
more modern appearance.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is nice to have so users know what to expect from each button. I do
take some liberties, such as putting version numbers of our dependencies
as the tooltip for the Title widget. I also display the current volume
level in the volume button tooltip.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I split the function into two. Calling env_string() will return the
string we generate with the versions of the various modules we depend
on. Calling print_env() will print this string.
I need env_string() so we can set the environment as a tooltip in the
header.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Future proof. If we update the database schema, then we'll bump the
user_version field. If the user then tries to open the new database with
an old Emmental version then there could be a lot of issues. Let's
detect this and raise an error with a description of the problem.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
These are used to manually rearrange the Tracks in the Playlist. The
buttons are only marked sensitive if one item is selected.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The Add Tracks button is a popover button configured to display a list
of playlists that tracks could be added to. I take some extra care to
make sure we only display playlists that have their user-tracks property
set to True, and to hide the currently visible playlist from the list.
Additionally, I create a horizontal size group so the Add and Remove
buttons are the same size.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The button is placed inside a Gtk.Overlay, and is hidden by default. The
button will be shown when tracks are selected if the current Playlist
has its "user-tracks" property set to True.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This widget displays the number of visible tracks, number of selected
tracks, and runtime of the current playlist. I wire it up to these
properties from the trackview.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is a Popover Button containing a Gtk.ListView to display the Sort
Order Model for the currently visible Playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This Widget is intended to be used as the child widget in a Gtk.ListView
to display and change the sort order of the current playlist. I use
arrow buttons from the icon library to represent sort order
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is a Gio.ListStore with some extra functions for enabling,
disabling, rearranging, and reversing sort fields. It also has a
sort-string property for getting the current sort order to save
to the database.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The SortField object is used to represent a single column in the
Tracklist that the user could sort by.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is an ImageToggle button that has been configured to cycle between
3 states corresponding to no looping, playlist looping, and track
looping.
I also update the Tracklist to look for changes in the visible Playlist
to update the Loop button.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The OSD will eventually contain buttons for modifying playlists, but for
now it just has functions and properties for mananging the current track
selection.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And wire this up to not only the Now Playing "jump" signal, but also the
next track pickers so we scroll when tracks are changed.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The MediumName TrackRow is used to combine the album and medium names
into a single string. This means we won't need to have a separate medium
name column that is empty for most tracks.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The AlbumCover shows a cover.jpg image for a specific Album in a column.
I also need to do some special handling so generate a tooltip to show a
larger version of the image.
I try to cache the AlbumCover Texture to cut down on disk accesses,
since we'll usually end up loading the same image several times for each
track in an album.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is an InscriptionRow that binds a Track's Album's property to the
Gtk.Inscription. I use it to display album artist and release information
in columns.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
These are specially configured TrackRows that take a non-string Track
property and convert it into a string displayed in the Inscription. I
use them to add Length, Play Count, Last Started, Last Played, and
Filepath columns to the TrackView.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The TrackRow widget is used to bind Tracks to a generic Widget. The
InscriptionRow builds on this to create a Gtk.Inscription that can be
used in derived classes. Finally, the TrackString widget implements
binding a string Track property directly to the Inscription.
I use these widgets to create a Title and Artist column in the
TrackView.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The TrackView sets up a scrollable Gtk.ColumnView inside a nice looking
frame. It also creates a FilterListModel for filtering tracks in a
separate layer from the Playlist so we don't affect choosing the next
track.
Finally, I add the TrackView to the TrackList Card.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
For now it only has the Gtk.CenterBox child with an entry.Filter widget,
but this will be expanded on in future patches. I also take the chance
to bind the factory:visible-playlist property to the playlist displayed
in the tracklist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And connect to the Player EOS and about-to-finish signals so we can
select the next track when the current one finishes (or slightly before
for gapless playback).
Implements: #7 (Add MPRIS2 Support)
Implements: #48 (Implement Intelligent ReplayGain)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
It takes an additional user= parameter to indicate if the user is asking
for the next track or if it is coming from the audio player (such as an
EOS / about-to-finish signal). This lets us handle the next_track() call
slightly differently for the user case.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And also a can-go-previous property to set the correct sensitivity on
the "Previous" button and for notifying MPRIS.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And add some special handling so a previous.Previous() playlist type is
created for the db_previous playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>