Commit Graph

295 Commits

Author SHA1 Message Date
Anna Schumaker 717fdf39cd tracklist: Add keyboard shortcuts
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>
2023-08-24 09:28:22 -04:00
Anna Schumaker 9cf980d967 emmental: Adjust active-row styling
Make the active row background color a little more transparent.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-08-24 09:28:22 -04:00
Anna Schumaker 87d8a2ae3a tracklist: Add tooltips to tracklist buttons
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-08-24 09:28:22 -04:00
Anna Schumaker ddfd37130b tracklist: Move the OSD out of the TrackView
This simplifies the code a lot by letting the TrackList directly call
OSD functions without going through the TrackView. I can also simplify
the TrackView to just contain our columnview.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-08-24 09:28:22 -04:00
Anna Schumaker 5011db344e tracklist: Rework the Add Tracks to Playlist button to use a ListBox
I also convert my PlaylistRowWidget into a Gtk.ListBoxRow that has the
same functionality. This looks a little nicer, and lets us keep the same
style as the rest of the app.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-08-24 09:28:22 -04:00
Anna Schumaker 9f240bbc8b tracklist: Rework the Sort Order button to use a ListBox
I convert my SortRow widget into a Gtk.ListBoxRow that has the same
functionality. The main benefit is that it looks nicer in the
Gtk.Popover compared to the Gtk.ListView that I had been using.

I also connect to the listbox "row-activated" signal so I can handle
clicking a specific sort row in the list. Clicking a disabled sort row
will enable it, and clicking an enabled one will reverse the sort order.
I think this is what feels the most natural to the user.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-08-24 09:28:22 -04:00
Anna Schumaker f6481f0182 tracklist: Rework the VisibleColumns button to use a ListBox
I create a custom Gtk.ListBoxRow for displaying each individual column
name and visibility status. I then bind it to a listbox placed as the
popover button's popover child. This lets me set the 'boxed-list' style
class on the listbox to give it a nicer appearance, and clicking the
label will also toggle column visibility.

Implements: #57 ("Rework visible columns button")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-08-24 09:28:06 -04:00
Anna Schumaker 3d6350d7bd tracklist: Give the Top Box the "toolbar" style class
And adjust widget spacing for to keep our nice look.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-08-22 13:29:53 -04:00
Anna Schumaker eb6b4d8ef4 buttons: Watch for ImageToggle tooltip text changes
If the application changes the active or inactive tooltip text, then we
want to apply that to the button depending on what state it currently
has.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-08-22 13:29:53 -04:00
Anna Schumaker f7349cd864 factory: Don't change Gtk ListRowWidget state flags
I was using this to set some custom styling for the active playlist and
track inside a ListView. I can accomplish the same thing by adding and
removing a style class from the ListRowWidget, and this doesn't break
Gtk internal stuff that changed in the 4.12 release.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-08-22 12:09:20 -04:00
Anna Schumaker ef99951f74 Emmental 3.0.5
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-30 09:26:14 -04:00
Anna Schumaker 0fd391a9fd sidebar: Add keyboard shortcuts
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>
2023-06-30 09:24:10 -04:00
Anna Schumaker bc92e72265 sidebar: Give the Header an activate() function
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-30 09:24:10 -04:00
Anna Schumaker 8dae0ed7bd sidebar: Add a button to jump to the current playlist
Implements: #59 ("Jump to Active Playlist button")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-30 09:23:31 -04:00
Anna Schumaker 1707f87e45 sidebar: Move the Filter into a Gtk.CenterBox
I'm going to add a button to jump to the current playlist, and the first
step is to add an area to put it in the sidebar.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-28 10:09:53 -04:00
Anna Schumaker 7e99fd1ba0 sidebar: Convert the section Group into a View
I change it to inherit from Gtk.Box, and append Sections as they are
added. I also add some stand-alone styling to set it apart as its own
widget.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-28 10:09:53 -04:00
Anna Schumaker a8e7078308 db: Disable incremental filtering
This applies to both the Table and child Playlists models. I'm doing my
own idle handling already for searching, so we can rely on that instead
of needing Gtk to do it. The benefit to this is that we can select
playlists programmatically during startup, since we don't need to worry
about the Table not being fully loaded yet.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-28 10:09:53 -04:00
Anna Schumaker 1d0813f217 db: Give playlist tables a refilter() function
This is used to notify the model that the rows have changed when it's
not automatically being detected. I first noticed this when attempting
to disable incremental filtering, due to the Artist list not getting
refiltered when new child Albums were added to the Artist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-28 10:09:53 -04:00
Anna Schumaker 725619faf5 db: Improve filtering Tables
I scheduled the filter query with  first=True so it can run without a
long delay during scanning. Additionally, I cancel any pending filter
calls to discard stale arguments that otherwise would be processed.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-28 10:09:53 -04:00
Anna Schumaker 6607e5b0ad db: Give the Idle Queue a way to handle high priority tasks
If we have a high priority task, then we want to push it to the front of
the idle queue so it runs as soon as possible.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-28 10:09:53 -04:00
Anna Schumaker 73019d8eb4 db: Give the Idle Queue a cancel_task() function
It's sometimes desireable to cancel a pending task and re-add it with
new parameters to cut out some unnecessary work.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-28 10:09:53 -04:00
Anna Schumaker 6032e549a5 emmental: Use the gsetup.DEBUG_STR for appending "-debug"
This lets us calculate if we're in debug-mode or not once, and reuse the
result when needed.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-28 10:06:38 -04:00
Anna Schumaker 06771ecab6 Emmental 3.0.4
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-23 15:51:03 -04:00
Anna Schumaker 17b2a82e20 db: Have Playlists use the child_set as the children base model
I combine this with the table's Filter object to show playlists matching
the current search query.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-23 11:37:47 -04:00
Anna Schumaker c0c516fb70 db: Have decade Playlists use the new child_set
I implement add_year(), remove_year(), and has_year() functions and make
sure we load the set of yearids during startup. Additionally, I have
Years add and remove themselves from Decades as they are created and
deleted.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-23 11:37:47 -04:00
Anna Schumaker 3cddde0986 db: Have Album playlists use the new child_set
I implement add_medium(), remove_medium(), and has_medium() functions
and make sure we load the set of mediumids during startup. Additionally,
I have Mediums add and remove themselves from Albums as they are created
and deleted.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-23 11:37:47 -04:00
Anna Schumaker 4f15bde850 db: Have Artist playlists use the new child_set
I switch over to adding and removing Albums using the generic
add_child() and remove_child() functions. I also switch from using a
KeySet filter holding albumids to a Gtk.CustomFilter that calls
Artist.has_album() to check if an Album is in the set.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-23 11:37:47 -04:00
Anna Schumaker 5ee86a9b5e db: Give the Media table a custom Filter
We want to filter out Medium playlists with empty names in the sidebar,
and the easiest way to do that is through a custom filter attached to
the Media table.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-23 11:37:47 -04:00
Anna Schumaker 85c18fb5fe db: Add a child_set TableSubset to the Playlist
It defaults to a None pointer, but calling add_children() will set one
up with an empty set. I also implement functions for adding, removing,
and verifying child playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-22 11:27:40 -04:00
Anna Schumaker 67b508384c db: Create a TableSubset model
This is similar to a Gtk.FilterListModel, except we already know exactly
which rows are part of the model or not. So we can skip the entire
filtering step and show rows directly instead.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-22 11:07:32 -04:00
Anna Schumaker 929beb2a97 db: Add set features to the KeySet
This includes implementing the __contains__() magic method, and adding
signals that are emitted when rows are added, removed, or directly set.
This will allow us to build a model around the rows represented by the
set.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-19 13:42:28 -04:00
Anna Schumaker f400366210 db: Rename the Table.Filter to Table.KeySet
I'm going to expand on this and use it for more than just filtering
Gtk.FilterListModels. Renaming it to something more generic is the first
step.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-19 09:55:11 -04:00
Anna Schumaker e846c957a5 Emmental 3.0.3
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-16 10:30:19 -04:00
Anna Schumaker 37f81825b1 sidebar: Give the New Playlist entry the "card" style class
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-16 10:17:38 -04:00
Anna Schumaker c375d2366a sidebar: Give sidebar widgets tooltip properties
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-10 21:30:43 -04:00
Anna Schumaker d807f8bd36 buttons: Replace the icon-size property with large-icon
It is much easier to pass a single boolean value instead of a Gtk
constant for specifying the icon size.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-10 21:30:41 -04:00
Anna Schumaker a13e481754 buttons: Give the ImageToggle active and inactive tooltip texts
This is used to set the tooltip text to fixed strings based on the
active status of the button. I also update the tooltip text on the
Favorite button in the Now Playing widget at the same time.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-10 20:31:41 -04:00
Anna Schumaker afb0ba5d68 buttons: Add missing docstring to the SplitButton.activate() function
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-10 19:28:24 -04:00
Anna Schumaker a6cd453c63 Emmental 3.0.2
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-09 10:31:35 -04:00
Anna Schumaker 7079076857 nowplaying: Add keyboard accelerators
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>
2023-06-09 10:25:00 -04:00
Anna Schumaker 8d72e1375f nowplaying: Give the Controls accelerator functions and properties
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>
2023-06-09 10:04:56 -04:00
Anna Schumaker 87b92ffc90 nowplaying: Give the autopause widgets {inc,dec}rement() functions
These will be used for keyboard accelerators to set the autopause value.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-09 10:04:51 -04:00
Anna Schumaker bb4ca1e9c4 nowplaying: Give the autopause entry the "card" style class
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-09 10:04:45 -04:00
Anna Schumaker 087c378e59 nowplaying: Remove the Gtk.Frame from the Artwork
All I needed the frame for was to add rounded corners to the
Gtk.Picture, but this had some problems with the Frame expanding beyond
the edges of the picture in some cases. I can get the same effect by
adding the "card" css class to the Picture so hopefully this will work
better.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-09 10:04:40 -04:00
Anna Schumaker 1f434358de nowplaying: Add tooltips to the Now Playing Card
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-09 10:04:34 -04:00
Anna Schumaker 41cb325ad0 buttons: Give the SplitButton an activate() function
This is a keybinding function that calls into the primary button
activate() function. At the same time, I add an "activate-primary"
signal that is emitted when the primary button is activated.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-09 10:04:28 -04:00
Anna Schumaker 0c1e5fcace header: Add keyboard accelerators
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>
2023-06-09 10:04:25 -04:00
Anna Schumaker 9cb927aabb header: Give the volume button public {inc,dec}rement() funcs
I made these functions part of the public interface with option
arguments so they can be used in accelerator callbacks for increasing or
decreasing the volume.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-09 09:50:22 -04:00
Anna Schumaker 397c693aef window: Add a keyboard accelerator
I use the "Escape" key as a shortcut for resetting the currently focused
widget.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-09 09:50:19 -04:00
Anna Schumaker eb162154b5 window: Add a "user-editing" property
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>
2023-06-09 09:46:10 -04:00
Anna Schumaker 2b5cdaa197 action: Add an ActionEntry class
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>
2023-06-09 09:45:58 -04:00
Anna Schumaker c5f9608c49 tracklist: Commit the database after adding, moving, or removing tracks
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>
2023-06-07 14:58:19 -04:00
Anna Schumaker cae93cae11 sidebar: Commit the database after creating a new playlist
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>
2023-06-07 14:58:19 -04:00
Anna Schumaker 01a37dbbc1 db: Commit the database after deleting a Table Row
Fixes: #63 ("The database isn't being committed enough")
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-06-07 14:54:32 -04:00
Anna Schumaker 14c487c295 db: Commit the database when a Track has been started or stopped
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>
2023-06-07 13:26:55 -04:00
Anna Schumaker 57dd2c280e db: Don't notify if the active-playlist doesn't change
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>
2023-06-06 09:29:16 -04:00
Anna Schumaker 59fb7d12f3 db: Set the Queued Tracks playlist as active when adding tracks
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>
2023-06-06 09:22:22 -04:00
Anna Schumaker 8afd1a6240 audio: Replace the playbin audio-filter with the new filter
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>
2023-06-01 11:13:48 -04:00
Anna Schumaker 84fbd94aa1 audio: Create a new audio filter for ReplayGain and Background Mode
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>
2023-06-01 11:13:46 -04:00
Anna Schumaker 7155fa9db5 header: Add an icon for background mode to the Header
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>
2023-06-01 11:13:44 -04:00
Anna Schumaker 0e40e6a4e8 header: Add a BackgroundRow to the popover menu
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>
2023-06-01 11:13:42 -04:00
Anna Schumaker deea9caa37 header: Create a BackgroundRow ListBox row
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>
2023-06-01 11:13:39 -04:00
Anna Schumaker a626a1f3c4 header: Convert the volume button box to a Gtk.ListBox
And give it the boxed-list style class so it looks nice.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-31 16:31:31 -04:00
Anna Schumaker dae588bfaf header: Convert the ReplayGain selector into an Adw.ExpanderRow
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>
2023-05-31 16:31:31 -04:00
Anna Schumaker 03e5b9ad1b header: Convert the volume controls into a ListBoxRow
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>
2023-05-31 16:31:30 -04:00
Anna Schumaker 5b0a0f54e4 header: Add tooltips to the Header widgets
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>
2023-05-30 13:54:21 -04:00
Anna Schumaker dd9d6268ff gsetup: Rework version string handling
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>
2023-05-30 13:19:51 -04:00
Anna Schumaker a86ce6165d Emmental: Add a MICRO_VERSION
And set it to '1' to start, since we have a few extra commits on top of
3.0 already.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-25 10:19:51 -04:00
Anna Schumaker 55d7eb3d45 db: Raise an exception if the user_version is too new
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>
2023-05-23 09:16:52 -04:00
Anna Schumaker 78ea2904a1 tracklist: Add Move Down and Move Up buttons to the OSD
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker a6f59d9378 tracklist: Add an Add Tracks button to the TrackView OSD
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker ff9724a274 tracklist: Add a Remove Tracks button to the TrackView
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 911aeb84a1 tracklist: Add a Footer widget
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker ee1152bcc4 tracklist: Add a SortButton
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker ed4a484a31 tracklist: Add a SortFieldWidget
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 83355f7e96 tracklist: Add a SortOrderModel
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker b326320156 tracklist: Add a SortField object
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 0c77e509c3 tracklist: Add a ShuffleButton
This is an ImageToggle button that adjusts its opacity based on if it is
active or not.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-10 17:42:27 -04:00
Anna Schumaker ed1d990e74 tracklist: Add a LoopButton
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 2d19d78eb6 tracklist: Add an Unselect All button
This button will unselect any selected tracks when clicked.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-10 17:42:27 -04:00
Anna Schumaker f1e18549ff tracklist: Add a VisibleColumns button
This button shows a popover menu to set the visibility of our columns.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-10 17:42:27 -04:00
Anna Schumaker ff1d772a05 tracklist: Add a Selection OSD to the TrackView
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker a485a3806b tracklist: Scroll to the requested Track
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 481c4856c7 tracklist: Request a Track when it is activated
And wire up a handler for the factory track-requested signal in the main
application code.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-10 17:42:27 -04:00
Anna Schumaker 61dfc2a586 tracklist: Create a MediumName TrackRow
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 97bf9d48db tracklist: Create an AlbumCover TrackRow
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker b3dcd3c0b9 tracklist: Create an AlbumString TrackRow
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 1ffc300eda tracklist: Create a TracknoString TrackRow
This is an InscriptionRow that combines a Track's number with its
Medium's number.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-10 17:42:27 -04:00
Anna Schumaker bed518cd77 tracklist: Create a FavoriteButton TrackRow
This button shows an ImageToggle button connected to the "favorite"
property of the Track.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-10 17:42:27 -04:00
Anna Schumaker 915a59a46b tracklist: Create LengthString, PlayCountString, TimestampString, and PathString TrackRows
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 9edfc4a5b0 tracklist: Create TrackRow, InscriptionRow, and TrackString widgets
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 999a3eb523 tracklist: Create a TrackView
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 2c2462c3d6 tracklist: Create a basic Tracklist widget
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>
2023-05-10 17:42:27 -04:00
Anna Schumaker 0d27a09233 emmental: Wire up the Next and Previous buttons
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>
2023-05-10 17:42:17 -04:00
Anna Schumaker a687b564a9 playlist: Give the Factory a track-requested signal
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-10 17:42:17 -04:00
Anna Schumaker 6bbc423193 playlist: Give the Factory a next_track() function
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>
2023-05-10 17:42:17 -04:00
Anna Schumaker cf056d6ec5 playlist: Give the Factory a previous_track() function
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>
2023-05-10 17:42:17 -04:00
Anna Schumaker fd584e516a playlist: Have the Factory create a previous Playlist
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>
2023-05-10 17:42:17 -04:00
Anna Schumaker 820eda4c46 playlist: Have the Factory create an active Playlist
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>
2023-05-10 17:42:17 -04:00
Anna Schumaker b0734a41d0 playlist: Have the Factory create a visible Playlist
I either create or reuse an existing Playlist object when the
db-visible property changes to a new value.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-10 17:42:17 -04:00