Allowing us to show and hide the sidebar by clicking the button in the
header. I also save the current state of the sidebar, although the
Adw.OverlaySplitView might override this when the window is shown.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The following shortcuts are implemented:
- Escape to unselect any selected tracks
- Delete to remove selected tracks from the current playlist
- <Control>/ to focus the "filter tracks" entry
- <Control>l to cycle the loop state of the current playlist
- <Control>s to toggle the shuffle state of the current playlist
- <Control>Up to move the selected track up one position
- <Control>Down to move the selected track down one position
I also change the volume up and down shortcuts to use the <Shift>
modifier. This matches how other Header shortcuts are triggered, and
frees up the non-shifted versions to use here.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The following shortcuts are implemented:
- <Control>? (<Shift><Control>/) to focus the "filter playlists" entry
- <Control><Alt>g to go to the current playlist
- <Shift><Control>p to open the Playlists section
- <Shift><Control>a to open the Artists section
- <Shift><Control>g to open the Genres section
- <Shift><Control>d to open the Decades section
- <Shift><Control>l to open the Libraries section
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I add accelerators for play, pause, next track, previous track, setting
autopause, adding the current track to the favorites playlist, and
scrolling to the current track in the tracklist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I create can-activate-* properties to indicate if a specific accelerator
can be activated. At the same time, I introduce functions intended to be
called by accelerators to activate each of our widgets.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I add accelerators for opening files, changing the volume, toggling
background mode, and running the settings editor.
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>
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>
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>
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 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>
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>
And add some special handling for setting the active playlist and
visible playlist to the same db playlist. I also add active-loop and
active-shuffle properties that are wired up to the MPRIS2 "Shuffle" and
"LoopStatus" player properties.
Implements: #7 (Add MPRIS2 Support)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The playlist factory has properties for the currently selected,
currently active, and previous playlists. It will eventually create
Gio.ListModel instances representing the tracks in each of these playlists,
in sorted order.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I attach these to the Now Playing card so the "add to favorites" button
can be correctly marked as sensitive and enabled when a Track is
selected for playback.
Additionally, I look for a notification from the Track table to say it
has been loaded. This lets me set the Player to load up the current_track
if one is set.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I make sure to save the "show-all" property to the settings so it can be
preserved across sessions.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
It only contains a FilterEntry for filtering future playlists. The
application will save its size when resized.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This Thread uses the audio.tagger.tag_file() function to find the tags
for a specific file without hanging the UI. There may be cases where we
have an Artist MBID but not the matching Artist name. When this happens,
I do my best to first check the database and then query the musicbrainz
server.
I take some care to only connect to the database once, and to close the
connection when the thread exits.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And use it to track the existence of artwork for the current file. This
could either be a cover.jpg file in the same directory as the currently
playing track or embedded artwork found in the Gst.TagList.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And wire it up to the Player through the Application.
Implements: #45 (Create a new NowPlaying widget)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And make sure we are able to watch for changes when tracks are loaded. I
also export it as mpris' mpris:length metadata field.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And wire up signals between the Now Playing card and the player.
Implements: #45 (Create a new NowPlaying widget)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
These functions are set up to take an unused argument list so they can
be connected to signals directly. I also add a 'playing' property to
track the current state of the playbin and a 'status' property to
translate 'playing' into something mpris understands.
Implements: #7 (Implement MPRIS2 Support)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And bind the Player tag properties to the Now Playing card.
Implements: #45 (Create a new NowPlaying widget)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I set these properties when the bus sends us tag messages, and wire them
up do the mpris2.Player object to notify dbus of their values.
These properties are cleared on both EOS and when a new file is started.
This is to account for the user changing the file mid-playback.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Either through the command line, mpris2, or the open button in the
header.
Implements: #7 (Add MPRIS2 Support)
Implements: #47 (Signal that the track has changed when it actually changes)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And wire it up to the Header and Mpris.Player so we can apply volume &
replaygain changes as they happen.
Implements: #42 ("Remove global audio.Player instance")
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>
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>
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 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 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>
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>