In this development diary, I provide an update on progress made on Koto in the second half of February 2021.
Full Steam Ahead
Since Dev Diary 2: Koto February Progress Report (A-side), which was originally released for Patrons on February 10th, significant progress has been made on all fronts, with almost all items I set out to accomplish in Dev Diary 2 being complete, including some improvements and changes that were not originally anticipated. Most of these changes happened across the 6 live streams I have done on my Twitch, with a few minor things happening “offline”. So let us dive into those changes!
UX Development Progression
The original goals I set out to accomplish in Dev Diary 2 for the rest of February specific to the user experience were:
- Migrate the KotoWindow and KotoHeaderBar away from using Glade UI templating.
KotoFlipperButtonto leverage our new
- Leverage the file indexer in building our the structures we have made currently, changing them as needed.
- Set up SASS / SCSS compilation and move existing styling from CSS to SASS, continuing to polish the user experience to reflect the mockup as time goes on.
I am happy to say that all of the above mentioned items have been implemented / accomplished.
Glade UI Templating
No longer do either the KotoWindow or KotoHeaderBar utilize Glade UI templating.
In the case of the KotoWindow, we simply changed to setting various properties using Gtk APIs, such as:
- Setting an initial size
- Setting the window title
- Setting our WM Class
- Setting our icon name (we are currently using
audio-headphonesuntil we have some sort of branding).
The work on the KotoWindow progressed further, after that original change from Glade UI templating. We now will set the optimal size of the window based on the screen resolution of the primary screen, if running under X11 where the relevant APIs are available. Further work will be done in the future to save the previous window state (dimension and position) if we are under X11 as well, though that will likely wait until I begin implementing our config. Here is a breakdown of how we set the default window size, which are all based on the width of the monitor and enforcing a 16:9 aspect ratio:
||Support 1366x768, 1440x900, and 1600x900|
||Support 3840x2160 and above|
I neither anticipate supporting nor desire to support anything below 1280px. The application is not designed for mobile and according to StatCounter, 1024x768 (as an example) makes up less than 3% of the global market. It is 2021 and I would argue that anything less than full HD should be treated with less priority. You really only see less than that, which it comes to new devices these days, on lower end laptops and Chromebooks. That does not mean I am wanting a bad experience on lesser resolutions, just that the focus really is on modern home computing.
In the case of the KotoHeaderBar, this class was deprecated due to the inability to sub-class GtkHeaderBar in GTK4, which I will be talking about in a moment! Instead, we just have a function that generates our HeaderBar and assigns the relevant controls related to the HeaderBar in our KotoWindow.
As I mentioned in my Dev Diary 2, I implemented a generic KotoButton class which merges our functionality for icon + image setting, text, desired CSS class styling, and more. One of the goals during the second half of February was to deprecate our
KotoFlipperButton class, implementing that image flip functionality in our KotoButton for use in our KotoExpander. This has been done.
Furthermore, the function
koto_create_flat_icon_button was deprecated, with KotoButton being used uniformly across all the relevant UX components now. All these aspects of the user experience now have clean, consistent code and functionality, and enables us to rapidly iterate on those applicable sections of the user experience thanks to numerous constructor APIs I implemented to ease button generation.
In Dev Diary 2, I discussed some of the issues I had with GTK4 removing sub-classing for GtkHeaderBar. This removal of sub-classing, as it turns out, also applied to the GtkScrolledWindow, which we leveraged in our KotoNav as its “parent instance” at the time of the Dev Diary 2 write-up.
As an unexpected turn of events, when we were implementing our Local Music view and our artist listing with our then GTK3-based implementation, we were continuously running into sporadic segfaults due to issues with the GtkListBox implementation in GTK3. Simply out of an act of necessity and desperation due to not being able to reliably “catch” these issues, I opted to see if porting the application to GTK4 would resolve the issue.
It did. We no longer have segfaults for something as simple as adding widgets to a ListBox. Yay!
The work to port from GTK3 to GTK4 was considerable even for what was, and still is in many ways, a fairly simple application at the time. Some examples:
- Since we no longer could sub-class GtkHeaderBar and GtkScrolledWindow, the opportunity was taken to deprecate KotoHeaderBar and have the relevant components inside the GtkHeaderBar be defined as members of our KotoWindow class. KotoHeaderBar may be re-introduced as a sub-class of a generic GObject class down the road if functionality expands beyond what is currently anticipated, but currently a function that generates the necessary widgets is sufficient. In the case of KotoNav, which uses the GtkScrolledWindow, we moved this to being a sub-class of the GObject class, with a
winstruct member being the relevant GtkScrolledWindow instead. That way we could still easily reference the GtkScrolledWindow itself.
- Per the GTK3 to GTK4 migration guide, various API changes were required. For example,
gtk_box_pack_endwere replaced with simpler
gtk_box_appendAPIs. I am really happy about this, I could never for the life of me remember the order of the expand and fill function variables in the older GTK3 box functions.
- In the KotoPlayerBar, we are now using the GtkCenterBox widget in GTK4 to set our primary controls, album art / playback section, and secondary controls, and enabling GTK4 to handle the layout for us. Effectively it will ensure the primary controls are always at the start / left of the KotoPlayerBar, secondary controls on the end / right, and playback section in the middle!
- Places we were using the button-release-event were changed to use the new GtkGesture and controller model, something I prefer over the GTK3 model.
- Creating icons which scale is far more trivial, despite the absolutely dreadful documentation surrounding the new GtkImage behavior and the numerous GdkPixbuf API deprecations. Instead of scaling down a GdkPixbuf, you just set the size of the GtkImage widget or its parent, or alternatively set the “pixel size” on the GtkImage, and GTK4 seems to handle the scaling for you!
So the tldr of all of this is, assuming nothing too crazy happens, Koto is likely to remain a GTK4 application. Color me surprised too.
Koto now uses SASS for its styling. SASS is a pre-processor for CSS, enabling us to take advantage of functionality not otherwise seen in CSS, such as: nesting, partials, mixins, separating out files, inheritance, and more. In the past, I have used LESS for various websites, whether that be my personal one or the Solus one. In Budgie Desktop, we use SASS, although as many of you know our internal theme has been stagnant for a while (for now, muahahaha) and we primarily use external themes like Plata for Budgie on Solus. But by-and-large I have not really needed to work with styling for GTK, so it was rather refreshing to start using SASS with Koto, informing me on the experience and providing me the opportunity to learn Gtk styling.
How exactly this will inform future developments remains to be seen. I totally have not teased a mockup of a redesign for Budgie Desktop’s internal theming and Budgie Menu in the past nor have I put any thought into creating a GTK3 and GTK4 theme focused on the desktop offerings and and experience of Solus + Budgie.
Nope, not at all. coughs /sarcasm
Various styling improvements / design refinements has been made since Dev Diary 2 as well. Padding / margins are consistent, font sizes are closer to the desired sizing used in our mockups, color and theming is more consistent even when using Adwaita, and more.
Building Our Local Music View
Throughout the second half of February, significant progress has been made on the Local Music view, the building of which has been the highest priority as work on the indexer and related structures progress. Since the release of Dev Diary 2 on Patreon (so February 10th), I have done the following:
- Implemented the primary Local Music layout in the form of the “Artists” navigation and per-artist album listings.
- Implemented the Artists navigation in the form of a GtkListBox, leveraging KotoButton internal to each GtkListBoxRow.
- Implemented our per-artist view with new KotoArtistView, KotoAlbumView and KotoDiscView components.
At this moment, our KotoPageMusicLocal is limited to setting one library. However as the functionality for multiple libraries is implemented, you will see this code get refactored and made more generic. For now, we iterate through each of the Artists in the assigned KotoIndexedLibrary, generating the KotoButton for use in the artist navigation, as well as the dedicated KotoArtistView component. The KotoArtistView component is responsible for generating our KotoAlbumView components for each Album by the Artist, which in turn is responsible for generating a KotoDiscView for each Disc / CD in an Album (since an Album can have multiple CDs / Discs).
This KotoDiscView will generate a track list based on the tracks in a given disc. Turtles all the way down.
Additionally, the KotoArtistView is designed to lay out our albums as a flowbox to maximize screen real estate usage.
Indexer and Database
Though building out Koto’s user experience was a considerable focus during the second half of February, it was not the singular focus. In Dev Diary 2, I mentioned the two non-UX goals I had for the upcoming weeks that I wanted to accomplish:
- Investigate various ID3 parsing libraries to determine the best to use (e.g. id3lib and taglib).
- Design the Sqlite database schema and begin to perform transactions based on our structured data.
In the case of ID3 parsing, we will now utilize the open source library known as TagLib for ID3v1 and ID3v2 metadata reading / writing. If we have valid ID3 data related to a track (whether that is an audiobook, music track, or podcast episode), we will use its “title” as our “parsed name”, set the artist and album, as well as set the position of the track based on any “track” tag defined.
In the case of the Sqlite3 database implementation, the beginning of the implementation of this happened fairly late into the development cycle. However, we are now able to create a Sqlite3 database in a sane location which respects the XDG Desktop Directories specification, so no random
.koto folder in your home directory! Looking as you, Firefox and Thunderbird.
We will store this database in the XDG Data “Home” directory, typically
.local/share/ under a
com.github.joshstrobl.koto folder, which respects the “reverse DNS” convention that is typically used desktop applications per the XDG Desktop Entry Specification. This file is simply called
db since no extension is required.
At the moment, we have set up the artists, albums, and tracks tables. The plan moving forward is to flesh out the rest of the database / table schema, writing our indexed filesystem data on first-run of Koto, and actually reading from the database into our KotoIndexedLibrary and relevant structures for use in Koto itself.
Besides the above mentioned accomplishments, improvements has been made to KotoIndexedFile when it comes to file name parsing. This code now uses a new, more consistent
koto_utils_get_filename_without_extension function and is slightly better at extrapolated the intended file name. There is still a bit of work to do on improving file name parsing but the current implementation covers most typical file names (and is only used as a fallback when ID3 metadata is unavailable).
During the first half of March, my goals are:
- Finish designing v1 of the database schema.
- Implement reading from and writing to the following tables: artists, albums, tracks.
- Introduce some minor refinements to file name parsing.
- Begin implementation of our KotoPlaylist structure, initially leveraging it as part of a “ephemeral” playlist like when you click to listen to an album.
- KotoPlaylist generation when we click to play a song or album. This requires some additional work on our KotoTrackItem component, event hookups, and more.
In the event these items are accomplished easier than expected, I will be moving on to “second half of March” items, primarily around KotoPlaylist and prototyping our audio playback!
Thank You For Your Support
As always, if you are contributing via Liberapay or Patreon, I want to thank you for your incredible support as I aim to achieve the goal of full-time open source development, with a focus on open source, modern desktop Linux computing. I hope these continued insights into development help to provide you confidence in this goal.
All development streams happen on my Twitch every Tuesday and Thursday from 12pm-5pm GMT+2 / EEST (Eastern European Standard Time). If you miss these streams, I upload all of them to Odysee so be sure to check them out! Since my last Dev Diary, the folks over at Odysee have added me to their Viewer Rewards Program, so if you have an Odysee account, you can now get a daily watch reward of a bit of LBRY Credits (LBC) when you watch my videos, and I get some too!
Here are the uploads from all the streams since Dev Diary 2 was released on Patreon!