summaryrefslogtreecommitdiff
path: root/data/ui
diff options
context:
space:
mode:
Diffstat (limited to 'data/ui')
-rw-r--r--data/ui/AlbumCover.ui63
-rw-r--r--data/ui/AlbumCoverListItem.ui50
-rw-r--r--data/ui/AlbumWidget.ui142
-rw-r--r--data/ui/AlbumsView.ui38
-rw-r--r--data/ui/AppMenu.ui84
-rw-r--r--data/ui/ArtistAlbumsWidget.ui20
-rw-r--r--data/ui/ArtistSearchTile.ui50
-rw-r--r--data/ui/ArtistTile.ui30
-rw-r--r--data/ui/ArtistsView.ui27
-rw-r--r--data/ui/DiscBox.ui36
-rw-r--r--data/ui/DiscListItem.ui29
-rw-r--r--data/ui/EmptyView.ui48
-rw-r--r--data/ui/HeaderBar.ui92
-rw-r--r--data/ui/LastfmDialog.ui62
-rw-r--r--data/ui/PlayerToolbar.ui203
-rw-r--r--data/ui/PlaylistControls.ui129
-rw-r--r--data/ui/PlaylistDialog.ui234
-rw-r--r--data/ui/PlaylistDialogRow.ui28
-rw-r--r--data/ui/PlaylistTile.ui33
-rw-r--r--data/ui/PlaylistsView.ui25
-rw-r--r--data/ui/PlaylistsWidget.ui36
-rw-r--r--data/ui/SearchHeaderBar.ui45
-rw-r--r--data/ui/SearchView.ui212
-rw-r--r--data/ui/SelectionBarMenuButton.ui22
-rw-r--r--data/ui/SelectionToolbar.ui16
-rw-r--r--data/ui/SongListItem.ui72
-rw-r--r--data/ui/SongWidget.ui207
-rw-r--r--data/ui/SongWidgetMenu.ui23
-rw-r--r--data/ui/SongsView.ui27
-rw-r--r--data/ui/TwoLineTip.ui23
-rw-r--r--data/ui/Window.ui54
-rw-r--r--data/ui/help-overlay.ui111
32 files changed, 2271 insertions, 0 deletions
diff --git a/data/ui/AlbumCover.ui b/data/ui/AlbumCover.ui
new file mode 100644
index 00000000..32c3ed17
--- /dev/null
+++ b/data/ui/AlbumCover.ui
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="AlbumCover" parent="GtkFlowBoxChild">
+ <child>
+ <object class="GtkBox">
+ <property name="focusable">False</property>
+ <property name="has_tooltip">True</property>
+ <property name="valign">start</property>
+ <property name="orientation">vertical</property>
+ <signal name="query-tooltip" handler="_on_tooltip_query"/>
+ <child>
+ <object class="GtkOverlay">
+ <property name="focusable">False</property>
+ <property name="margin-bottom">4</property>
+ <child>
+ <object class="GtkImage" id="_cover_image">
+ <property name="focusable">False</property>
+ <property name="vexpand">True</property>
+ <property name="valign">end</property>
+ <property name="halign">center</property>
+ </object>
+ </child>
+ <child type="overlay">
+ <object class="GtkCheckButton" id="_check">
+ <property name="focusable">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">end</property>
+ <property name="valign">end</property>
+ <style>
+ <class name="selection-mode"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_title_label">
+ <property name="focusable">False</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">middle</property>
+ <property name="max_width_chars">20</property>
+ <property name="lines">2</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_artist_label">
+ <property name="focusable">False</property>
+ <property name="ellipsize">middle</property>
+ <property name="max_width_chars">20</property>
+ <style>
+ <class name="albumcover-artist-label"/>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <style>
+ <class name="tile"/>
+ </style>
+ </template>
+</interface>
diff --git a/data/ui/AlbumCoverListItem.ui b/data/ui/AlbumCoverListItem.ui
new file mode 100644
index 00000000..8fa7acce
--- /dev/null
+++ b/data/ui/AlbumCoverListItem.ui
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <object class="GtkBox" id="_album_cover">
+ <property name="has_tooltip">True</property>
+ <property name="valign">start</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkOverlay">
+ <property name="margin-bottom">6</property>
+ <child>
+ <object class="GtkImage" id="_cover_image">
+ <property name="vexpand">True</property>
+ <property name="valign">center</property>
+ <property name="halign">center</property>
+ </object>
+ </child>
+ <child type="overlay">
+ <object class="GtkCheckButton" id="_check">
+ <property name="visible">False</property>
+ <property name="halign">end</property>
+ <property name="valign">end</property>
+ <style>
+ <class name="selection-mode"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">middle</property>
+ <property name="max_width_chars">20</property>
+ <property name="lines">2</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_artist_label">
+ <property name="ellipsize">middle</property>
+ <property name="max_width_chars">20</property>
+ <style>
+ <class name="albumcover-artist-label"/>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/data/ui/AlbumWidget.ui b/data/ui/AlbumWidget.ui
new file mode 100644
index 00000000..0dc30d0f
--- /dev/null
+++ b/data/ui/AlbumWidget.ui
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="AlbumWidget" parent="AdwBin">
+ <child>
+ <object class="AdwClamp">
+ <property name="margin-bottom">48</property>
+ <property name="margin-top">48</property>
+ <property name="maximum-size">1000</property>
+ <child>
+ <object class="GtkBox">
+ <property name="halign">fill</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="albumInfo">
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">32</property>
+ <child>
+ <object class="GtkImage" id="_cover_image">
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="albumDetails">
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <property name="orientation">vertical</property>
+ <property name="margin-top">18</property>
+ <child>
+ <object class="GtkLabel" id="_title_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="ellipsize">middle</property>
+ <property name="margin-bottom">18</property>
+ <style>
+ <class name="title-1"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_artist_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="ellipsize">middle</property>
+ <property name="margin-bottom">12</property>
+ <style>
+ <class name="title-3"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_released_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="use_markup">True</property>
+ <property name="margin-bottom">12</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_composer_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="ellipsize">end</property>
+ <property name="margin-bottom">12</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="spacing">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkButton" id="_play_button">
+ <property name="width-request">44</property>
+ <property name="height-request">44</property>
+ <property name="icon-name">media-playback-start-symbolic</property>
+ <property name="tooltip-text" translatable="yes">Play</property>
+ <property name="valign">center</property>
+ <signal name="clicked" handler="_on_play_button_clicked" swapped="no"/>
+ <style>
+ <class name="circular"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="_menu_button">
+ <property name="width-request">44</property>
+ <property name="height-request">44</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="focus_on_click">False</property>
+ <property name="menu-model">album_menu</property>
+ <property name="direction">none</property>
+ <property name="icon_name">view-more-symbolic</property>
+ <style>
+ <class name="circular"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="_disc_list_box">
+ <property name="focusable">False</property>
+ <property name="margin-top">48</property>
+ <property name="selection_mode">0</property>
+ <style>
+ <class name="background"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ <menu id="album_menu">
+ <item>
+ <attribute name="label" translatable="yes">_Play</attribute>
+ <attribute name="action">album.play</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Add to _Favorite Songs</attribute>
+ <attribute name="action">album.add_favorites</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Add to Playlist…</attribute>
+ <attribute name="action">album.add_playlist</attribute>
+ </item>
+ </menu>
+</interface>
diff --git a/data/ui/AlbumsView.ui b/data/ui/AlbumsView.ui
new file mode 100644
index 00000000..5523af53
--- /dev/null
+++ b/data/ui/AlbumsView.ui
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template class="AlbumsView" parent="GtkStack">
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">grid</property>
+ <property name="child">
+ <object class="GtkScrolledWindow" id="_scrolled_window">
+ <child>
+ <object class="GtkGridView" id="_gridview">
+ <property name="max-columns">10</property>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">widget</property>
+ <property name="child">
+ <object class="GtkScrolledWindow" id="_album_scrolled_window">
+ <property name="focusable">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="scroll-to-focus">True</property>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/AppMenu.ui b/data/ui/AppMenu.ui
new file mode 100644
index 00000000..70f9e7f5
--- /dev/null
+++ b/data/ui/AppMenu.ui
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="AppMenu" parent="GtkPopover">
+ <property name="focusable">False</property>
+ <style>
+ <class name="menu"/>
+ </style>
+ <child>
+ <object class="GtkBox">
+ <property name="focusable">False</property>
+ <property name="margin-bottom">6</property>
+ <property name="margin-end">6</property>
+ <property name="margin-start">6</property>
+ <property name="margin-top">6</property>
+ <property name="spacing">6</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkModelButton" id="lastfm_account_button">
+ <property name="focusable">False</property>
+ <property name="halign">fill</property>
+ <property name="hexpand">False</property>
+ <property name="action_name">app.lastfm-configure</property>
+ <property name="text" translatable="yes">Last.fm Account</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="_lastfm_box">
+ <property name="margin-end">5</property>
+ <property name="visible">False</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="focusable">False</property>
+ <property name="margin-end">12</property>
+ <property name="halign">start</property>
+ <property name="hexpand">False</property>
+ <property name="label" translatable="yes">Report Music Listening</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="_lastfm_switch">
+ <property name="focusable">True</property>
+ <property name="halign">end</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparator">
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton" id="_keyboard_shortcuts_model_button">
+ <property name="halign">fill</property>
+ <property name="hexpand">False</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">win.show-help-overlay</property>
+ <property name="text" translatable="yes">_Keyboard Shortcuts</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton" id="_help_model_button">
+ <property name="halign">fill</property>
+ <property name="hexpand">False</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">app.help</property>
+ <property name="text" translatable="yes">_Help</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton" id="_about_model_button">
+ <property name="halign">fill</property>
+ <property name="hexpand">False</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">app.about</property>
+ <property name="text" translatable="yes">_About Music</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/ArtistAlbumsWidget.ui b/data/ui/ArtistAlbumsWidget.ui
new file mode 100644
index 00000000..f38c85b9
--- /dev/null
+++ b/data/ui/ArtistAlbumsWidget.ui
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template class="ArtistAlbumsWidget" parent="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="AdwClamp">
+ <property name="maximum-size">1000</property>
+ <property name="orientation">horizontal</property>
+ <child>
+ <object class="GtkListBox" id="_listbox">
+ <style>
+ <class name="background"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/ArtistSearchTile.ui b/data/ui/ArtistSearchTile.ui
new file mode 100644
index 00000000..e95d950f
--- /dev/null
+++ b/data/ui/ArtistSearchTile.ui
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ArtistSearchTile" parent="GtkFlowBoxChild">
+ <child>
+ <object class="GtkBox">
+ <property name="has_tooltip">True</property>
+ <property name="valign">start</property>
+ <property name="orientation">vertical</property>
+ <signal name="query-tooltip" handler="_on_tooltip_query" swapped="no"/>
+ <child>
+ <object class="GtkOverlay">
+ <property name="margin-bottom">4</property>
+ <child>
+ <object class="GtkImage" id="_cover_image">
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkGestureClick">
+ <signal name="released" handler="_on_artist_event" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="overlay">
+ <object class="GtkCheckButton" id="_check">
+ <property name="receives_default">False</property>
+ <property name="halign">end</property>
+ <property name="valign">end</property>
+ <style>
+ <class name="selection-mode"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_artist_label">
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">middle</property>
+ <property name="max_width_chars">20</property>
+ <property name="lines">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <style>
+ <class name="tile"/>
+ </style>
+ </template>
+</interface>
diff --git a/data/ui/ArtistTile.ui b/data/ui/ArtistTile.ui
new file mode 100644
index 00000000..e10f2b76
--- /dev/null
+++ b/data/ui/ArtistTile.ui
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ArtistTile" parent="GtkBox">
+ <property name="focusable">False</property>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="margin-start">10</property>
+ <child>
+ <object class="GtkImage" id="_cover_image">
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_label">
+ <property name="focusable">False</property>
+ <property name="ellipsize">end</property>
+ <property name="halign">start</property>
+ <property name="hexpand">False</property>
+ <property name="margin-bottom">16</property>
+ <property name="margin-end">10</property>
+ <property name="margin-start">10</property>
+ <property name="margin-top">16</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/ArtistsView.ui b/data/ui/ArtistsView.ui
new file mode 100644
index 00000000..8053288f
--- /dev/null
+++ b/data/ui/ArtistsView.ui
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template class="ArtistsView" parent="GtkPaned">
+ <property name="shrink-start-child">0</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="width_request">220</property>
+ <child>
+ <object class="GtkListView" id="_sidebar">
+ <property name="single-click-activate">True</property>
+ <signal name="activate" handler="_on_artist_activated" swapped="no"/>
+ <style>
+ <class name="navigation-sidebar"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="_artist_view">
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/DiscBox.ui b/data/ui/DiscBox.ui
new file mode 100644
index 00000000..4899ecf8
--- /dev/null
+++ b/data/ui/DiscBox.ui
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template parent="GtkListBoxRow" class="DiscBox">
+ <property name="focusable">False</property>
+ <property name="activatable">False</property>
+ <property name="selectable">False</property>
+ <child>
+ <object class="GtkBox">
+ <property name="focusable">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="_disc_label">
+ <property name="focusable">False</property>
+ <property name="halign">fill</property>
+ <property name="xalign">0.0</property>
+ <style>
+ <class name="disc-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="_list_box">
+ <property name="focusable">False</property>
+ <property name="valign">start</property>
+ <property name="selection_mode">none</property>
+ <signal name="row-activated" handler="_song_activated" swapped="no"/>
+ <style>
+ <class name="boxed-list"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/DiscListItem.ui b/data/ui/DiscListItem.ui
new file mode 100644
index 00000000..dd3c85f3
--- /dev/null
+++ b/data/ui/DiscListItem.ui
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="4.0"/>
+ <template class="DiscListItem" parent="GtkListItem">
+ <property name="child">
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel">
+ <binding name="label">
+ <lookup name="disc_nr" type="CoreDisc">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ <child>
+ <object class="DiscBox" id="_disc_box">
+ <binding name="model">
+ <lookup name="model" type="CoreDisc">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ </object>
+ </property>
+ </template>
+</interface>
diff --git a/data/ui/EmptyView.ui b/data/ui/EmptyView.ui
new file mode 100644
index 00000000..ea571e10
--- /dev/null
+++ b/data/ui/EmptyView.ui
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="EmptyView" parent="GtkStack">
+ <property name="visible">False</property>
+ <child>
+ <object class="AdwStatusPage" id="_status_page">
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="icon_name">emblem-music-symbolic</property>
+ </object>
+ </child>
+ </template>
+ <object class="AdwClamp" id="_initial_state">
+ <property name="maximum-size">620</property>
+ <property name="tightening-threshold">500</property>
+ <child>
+ <object class="GtkBox">
+ <property name="valign">start</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkPicture">
+ <property name="can-shrink">true</property>
+ <property name="keep-aspect-ratio">true</property>
+ <property name="file">resource:///org/gnome/Music/icons/welcome-music.svg</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_title_label">
+ <property name="justify">center</property>
+ <property name="label" translatable="yes">Welcome to Music</property>
+ <style>
+ <class name="title-1"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_description_label">
+ <property name="justify">center</property>
+ <property name="use-markup">True</property>
+ <style>
+ <class name="body"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/data/ui/HeaderBar.ui b/data/ui/HeaderBar.ui
new file mode 100644
index 00000000..7064e406
--- /dev/null
+++ b/data/ui/HeaderBar.ui
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.10 -->
+ <template class="HeaderBar" parent="AdwBin">
+ <child>
+ <object class="AdwHeaderBar" id="_headerbar">
+ <property name="vexpand">False</property>
+ <style>
+ <class name="titlebar"/>
+ </style>
+ <child type="end">
+ <object class="GtkMenuButton" id="_menu_button">
+ <property name="valign">center</property>
+ <property name="sensitive">True</property>
+ <property name="icon-name">open-menu-symbolic</property>
+ <property name="primary">True</property>
+ <property name="tooltip_text" translatable="yes">Menu</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkToggleButton" id="_select_button">
+ <property name="valign">center</property>
+ <property name="sensitive">True</property>
+ <property name="icon-name">selection-mode-symbolic</property>
+ <property name="tooltip_text" translatable="yes">Select</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkButton" id="_cancel_button">
+ <property name="visible">False</property>
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="use_underline">True</property>
+ <property name="valign">center</property>
+ <property name="sensitive">True</property>
+ <signal name="clicked" handler="_on_cancel_button_clicked" swapped="no"/>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkToggleButton" id="_search_button">
+ <property name="valign">center</property>
+ <property name="sensitive">True</property>
+ <property name="icon-name">edit-find-symbolic</property>
+ <property name="tooltip_text" translatable="yes">Search</property>
+ </object>
+ </child>
+ <child type="start">
+ <object class="GtkButton" id="_back_button">
+ <property name="valign">center</property>
+ <property name="sensitive">True</property>
+ <property name="icon-name">go-previous-symbolic</property>
+ <property name="tooltip_text" translatable="yes">Back</property>
+ <signal name="clicked" handler="_on_back_button_clicked" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkBox" id="_label_title_box">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="_label_title">
+ <property name="single-line-mode">True</property>
+ <property name="ellipsize">end</property>
+ <property name="width-chars">5</property>
+ <property name="vexpand">True</property>
+ <property name="yalign">1.0</property>
+ <style>
+ <class name="title"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_label_subtitle">
+ <property name="single-line-mode">True</property>
+ <property name="ellipsize">end</property>
+ <property name="width-chars">5</property>
+ <property name="vexpand">True</property>
+ <property name="yalign">0.0</property>
+ <style>
+ <class name="subtitle"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="size1">
+ <property name="mode">vertical</property>
+ <widgets>
+ <widget name="_search_button"/>
+ <widget name="_cancel_button"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/data/ui/LastfmDialog.ui b/data/ui/LastfmDialog.ui
new file mode 100644
index 00000000..926c7872
--- /dev/null
+++ b/data/ui/LastfmDialog.ui
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="LastfmDialog" parent="GtkDialog">
+ <property name="focusable">False</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="modal">True</property>
+ <property name="resizable">False</property>
+ <property name="title" translatable="yes">Last.fm Account</property>
+ <property name="valign">start</property>
+ <child internal-child="content_area">
+ <object class="GtkBox">
+ <property name="margin-bottom">16</property>
+ <property name="margin-end">16</property>
+ <property name="margin-start">16</property>
+ <property name="margin-top">16</property>
+ <property name="orientation">vertical</property>
+ <property name="valign">start</property>
+ <child>
+ <object class="GtkLabel" id="introduction_label">
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Last.fm is a music discovery service that gives you personalised recommendations based on the music you listen to.</property>
+ <property name="margin-bottom">16</property>
+ <property name="max_width_chars">60</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_status_label">
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Music Reporting Not Setup</property>
+ <property name="margin-bottom">8</property>
+ <property name="max_width_chars">60</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="lastfm-status-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_action_label">
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Login to your Last.fm account to report your music listening.</property>
+ <property name="margin-bottom">12</property>
+ <property name="max_width_chars">60</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="_action_button">
+ <signal name="clicked" handler="_on_action_button_clicked" swapped="no"/>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Login</property>
+ <property name="margin-bottom">8</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/PlayerToolbar.ui b/data/ui/PlayerToolbar.ui
new file mode 100644
index 00000000..39616b80
--- /dev/null
+++ b/data/ui/PlayerToolbar.ui
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template class="PlayerToolbar" parent="GtkActionBar">
+ <property name="focusable">False</property>
+ <property name="revealed">False</property>
+ <child>
+ <object class="GtkBox" id="_song_info_box">
+ <property name="focusable">False</property>
+ <property name="halign">center</property>
+ <property name="has_tooltip">True</property>
+ <property name="valign">center</property>
+ <property name="spacing">8</property>
+ <property name="margin-bottom">6</property>
+ <property name="margin-end">6</property>
+ <property name="margin-start">6</property>
+ <property name="margin-top">6</property>
+ <signal name="query-tooltip" handler="_on_tooltip_query"/>
+ <child>
+ <object class="GtkImage" id="_cover_image">
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="nowplaying_labels">
+ <property name="focusable">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="orientation">vertical</property>
+ <property name="homogeneous">True</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="_title_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="ellipsize">middle</property>
+ <property name="max_width_chars">28</property>
+ <attributes>
+ <attribute name="weight" value="bold" />
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_artist_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="ellipsize">middle</property>
+ <property name="max_width_chars">28</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="center">
+ <object class="GtkBox" id="_buttons_and_scale">
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="focusable">False</property>
+ <property name="margin-bottom">6</property>
+ <property name="margin-end">6</property>
+ <property name="margin-start">6</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkBox" id="buttons">
+ <property name="focusable">False</property>
+ <property name="halign">center</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkButton" id="_prev_button">
+ <property name="sensitive">False</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <property name="icon_name">media-skip-backward-symbolic</property>
+ <property name="tooltip_text" translatable="yes">Previous</property>
+ <property name="valign">center</property>
+ <signal name="clicked" handler="_on_prev_button_clicked" swapped="no"/>
+ <style>
+ <class name="circular"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="_play_button">
+ <property name="sensitive">False</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Play</property>
+ <signal name="clicked" handler="_on_play_button_clicked" swapped="no"/>
+ <style>
+ <class name="pill"/>
+ </style>
+ <child>
+ <object class="GtkImage" id="_play_pause_image">
+ <property name="icon_name">media-playback-start-symbolic</property>
+ <property name="icon_size">2</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="_next_button">
+ <property name="sensitive">False</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <property name="icon_name">media-skip-forward-symbolic</property>
+ <property name="tooltip_text" translatable="yes">Next</property>
+ <property name="valign">center</property>
+ <signal name="clicked" handler="_on_next_button_clicked" swapped="no"/>
+ <style>
+ <class name="circular"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwClamp">
+ <property name="maximum-size">1000</property>
+ <child>
+ <object class="GtkBox" id="scale_and_timer">
+ <property name="orientation">horizontal</property>
+ <property name="focusable">False</property>
+ <property name="margin_top">12</property>
+ <child>
+ <object class="GtkLabel" id="_progress_time_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="label">0∶00</property>
+ <attributes>
+ <attribute name="font-features" value="tnum=1"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="SmoothScale" id="_progress_scale">
+ <property name="focusable">True</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="draw_value">False</property>
+ <signal name = "value-changed" handler="_on_progress_value_changed" swapped="no"/>
+ <style>
+ <class name="smooth-scale"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_duration_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="label">0∶00</property>
+ <attributes>
+ <attribute name="font-features" value="tnum=1"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkBox" id="menuBox">
+ <property name="height_request">34</property>
+ <property name="focusable">False</property>
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <property name="margin-bottom">6</property>
+ <property name="margin-end">6</property>
+ <property name="margin-start">6</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkMenuButton" id="_repeat_menu_button">
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <child>
+ <object class="GtkBox" id="replayBox">
+ <property name="focusable">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="_repeat_image">
+ <property name="focusable">False</property>
+ <property name="icon_name">media-playlist-consecutive-symbolic</property>
+ <property name="icon_size">1</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage" id="downArrow">
+ <property name="focusable">False</property>
+ <property name="icon_name">pan-down-symbolic</property>
+ <property name="icon_size">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/PlaylistControls.ui b/data/ui/PlaylistControls.ui
new file mode 100644
index 00000000..04ea750b
--- /dev/null
+++ b/data/ui/PlaylistControls.ui
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <menu id="playlistMenu">
+ <item>
+ <attribute name="label" translatable="yes">_Play</attribute>
+ <attribute name="action">win.playlist_play</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Delete</attribute>
+ <attribute name="action">win.playlist_delete</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Rename…</attribute>
+ <attribute name="action">win.playlist_rename</attribute>
+ </item>
+ </menu>
+ <template class="PlaylistControls" parent="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="focusable">False</property>
+ <property name="margin-top">30</property>
+ <child>
+ <object class="GtkStack" id="_name_stack">
+ <child>
+ <object class="GtkLabel" id="_name_label">
+ <property name="focusable">False</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Playlist Name</property>
+ <property name="ellipsize">middle</property>
+ <property name="margin-bottom">10</property>
+ <style>
+ <class name="title-1"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">renaming_dialog</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <style>
+ <class name="linked"/>
+ </style>
+ <child>
+ <object class="GtkEntry" id="_rename_entry">
+ <child>
+ <object class="GtkEventControllerKey" id="_rename_controller">
+ <signal name="key-pressed" handler="_on_rename_entry_key_pressed" swapped="no"/>
+ </object>
+ </child>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <signal name="activate" handler="_on_playlist_renamed" swapped="no"/>
+ <signal name="changed" handler="_on_rename_entry_changed" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="_rename_done_button">
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">_Done</property>
+ <property name="use_underline">True</property>
+ <property name="sensitive">True</property>
+ <signal name="clicked" handler="_on_playlist_renamed" swapped="no" />
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_songs_count_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="label"></property>
+ <property name="margin-bottom">4</property>
+ <style>
+ <class name="body"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="spacing">12</property>
+ <property name="margin-top">18</property>
+ <property name="margin-bottom">8</property>
+ <child>
+ <object class="GtkButton" id="_play_button">
+ <property name="height-request">44</property>
+ <property name="width-request">44</property>
+ <property name="focusable">True</property>
+ <property name="receives-default">True</property>
+ <property name="icon_name">media-playback-start-symbolic</property>
+ <property name="tooltip-text" translatable="yes">Play</property>
+ <property name="valign">center</property>
+ <signal name="clicked" handler="_on_play_button_clicked" swapped="no"/>
+ <style>
+ <class name="circular"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="_menubutton">
+ <property name="height-request">44</property>
+ <property name="width-request">44</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="focus_on_click">False</property>
+ <property name="menu-model">playlistMenu</property>
+ <property name="direction">none</property>
+ <property name="icon_name">view-more-symbolic</property>
+ <style>
+ <class name="circular"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/PlaylistDialog.ui b/data/ui/PlaylistDialog.ui
new file mode 100644
index 00000000..51e58c87
--- /dev/null
+++ b/data/ui/PlaylistDialog.ui
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template class="PlaylistDialog" parent="GtkDialog">
+ <property name="width_request">400</property>
+ <property name="height_request">500</property>
+ <property name="focusable">False</property>
+ <property name="modal">True</property>
+ <property name="destroy_with_parent">True</property>
+ <child internal-child="content_area">
+ <object class="GtkBox" id="dialog-vbox">
+ <property name="focusable">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStack" id="_add_playlist_stack">
+ <property name="focusable">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="transition_duration">250</property>
+ <child>
+ <object class="GtkBox" id="_empty_box">
+ <property name="visible">False</property>
+ <property name="focusable">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox">
+ <property name="focusable">False</property>
+ <property name="orientation">vertical</property>
+ <property name="valign">fill</property>
+ <property name="vexpand">True</property>
+ <property name="margin-bottom">18</property>
+ <property name="margin-end">18</property>
+ <property name="margin-start">18</property>
+ <property name="margin-top">18</property>
+ <child>
+ <object class="GtkImage" id="image">
+ <property name="focusable">False</property>
+ <property name="valign">center</property>
+ <property name="pixel_size">100</property>
+ <property name="icon_name">emblem-music-symbolic</property>
+ <property name="icon_size">0</property>
+ <property name="margin-bottom">16</property>
+ <property name="vexpand">True</property>
+ <style>
+ <class name="grey-image"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="focusable">False</property>
+ <property name="label" translatable="yes">Enter a name for your first playlist</property>
+ <property name="valign">end</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkEntry" id="_first_playlist_entry">
+ <property name="width_request">300</property>
+ <property name="height_request">10</property>
+ <property name="focusable">True</property>
+ <property name="halign">center</property>
+ <property name="margin-bottom">16</property>
+ <property name="margin-end">18</property>
+ <property name="margin-start">18</property>
+ <property name="margin-top">18</property>
+ <signal name="activate" handler="_on_editing_done" swapped="no"/>
+ <signal name="changed" handler="_on_add_playlist_entry_changed" swapped="no"/>
+ <child>
+ <object class="GtkEventControllerFocus">
+ <signal name="enter" handler="_on_add_playlist_entry_focused" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="_first_playlist_button">
+ <property name="label" translatable="yes">C_reate</property>
+ <property name="use_underline">True</property>
+ <property name="width_request">120</property>
+ <property name="height_request">25</property>
+ <property name="sensitive">False</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="margin-bottom">20</property>
+ <property name="margin-end">18</property>
+ <property name="margin-start">18</property>
+ <property name="margin-top">10</property>
+ <signal name="clicked" handler="_on_editing_done" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="focusable">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="_normal_box">
+ <property name="visible">False</property>
+ <property name="focusable">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow">
+ <property name="focusable">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="scroll-to-focus">True</property>
+ <child>
+ <object class="GtkListBox" id="_listbox">
+ <property name="focusable">True</property>
+ <property name="selection_mode">single</property>
+ <property name="valign">start</property>
+ <signal name="selected-rows-changed" handler="_on_selected_rows_changed" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="focusable">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkSeparator">
+ <property name="focusable">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="new-playlist-hbox">
+ <property name="focusable">False</property>
+ <property name="margin-bottom">6</property>
+ <property name="margin-end">6</property>
+ <property name="margin-start">6</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkEntry" id="_new_playlist_entry">
+ <property name="focusable">True</property>
+ <property name="hexpand">True</property>
+ <property name="placeholder_text" translatable="yes">New Playlist…</property>
+ <signal name="activate" handler="_on_editing_done" swapped="no"/>
+ <signal name="changed" handler="_on_add_playlist_entry_changed" swapped="no"/>
+ <style>
+ <class name="linked"/>
+ </style>
+ <child>
+ <object class="GtkEventControllerFocus">
+ <signal name="enter" handler="_on_add_playlist_entry_focused" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="_new_playlist_button">
+ <property name="label" translatable="yes">Add</property>
+ <property name="sensitive">False</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">False</property>
+ <signal name="clicked" handler="_on_editing_done" swapped="no"/>
+ <style>
+ <class name="suggested-action"/>
+ <class name="linked"/>
+ </style>
+ </object>
+ </child>
+ <style>
+ <class name="linked"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="focusable">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkBox">
+ <property name="focusable">False</property>
+ <property name="visible">False</property>
+ </object>
+ </child>
+ </template>
+ <object class="GtkHeaderBar" id="_title_bar">
+ <property name="focusable">False</property>
+ <property name="show_title_buttons">False</property>
+ <property name="title-widget">
+ <object class="GtkLabel">
+ <property name="label" translatable="yes">Add to Playlist</property>
+ <property name="single-line-mode">True</property>
+ <property name="ellipsize">end</property>
+ <property name="width-chars">5</property>
+ <style>
+ <class name="title"/>
+ </style>
+ </object>
+ </property>
+ <child>
+ <object class="GtkButton" id="_cancel_button">
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="use_underline">True</property>
+ <property name="focusable">False</property>
+ <property name="receives_default">False</property>
+ <signal name="clicked" handler="_on_cancel_button_clicked" swapped="no"/>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkButton" id="_select_button">
+ <property name="label" translatable="yes">_Add</property>
+ <property name="sensitive">False</property>
+ <property name="use_underline">True</property>
+ <property name="focusable">False</property>
+ <property name="receives_default">False</property>
+ <signal name="clicked" handler="_on_selection" swapped="no"/>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/data/ui/PlaylistDialogRow.ui b/data/ui/PlaylistDialogRow.ui
new file mode 100644
index 00000000..c9c96175
--- /dev/null
+++ b/data/ui/PlaylistDialogRow.ui
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="PlaylistDialogRow" parent="GtkListBoxRow">
+ <style>
+ <class name="playlistdialog-row"/>
+ </style>
+ <child>
+ <object class="GtkBox" id="hbox">
+ <child>
+ <object class="GtkLabel" id="_label">
+ <property name="ellipsize">end</property>
+ <property name="margin-bottom">8</property>
+ <property name="margin-end">8</property>
+ <property name="margin-start">8</property>
+ <property name="margin-top">8</property>
+ <property name="xalign">0.0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage" id="_selection_icon">
+ <property name="icon-name">selection-mode-symbolic</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/PlaylistTile.ui b/data/ui/PlaylistTile.ui
new file mode 100644
index 00000000..2375857f
--- /dev/null
+++ b/data/ui/PlaylistTile.ui
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="PlaylistTile" parent="GtkListBoxRow">
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="margin-start">10</property>
+ <child>
+ <object class="GtkImage" id="_icon">
+ <property name="focusable">False</property>
+ <property name="icon-size">normal</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="playlist-icon"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_label">
+ <property name="focusable">False</property>
+ <property name="ellipsize">end</property>
+ <property name="halign">start</property>
+ <property name="hexpand">False</property>
+ <property name="margin-bottom">16</property>
+ <property name="margin-end">10</property>
+ <property name="margin-start">10</property>
+ <property name="margin-top">16</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/PlaylistsView.ui b/data/ui/PlaylistsView.ui
new file mode 100644
index 00000000..a1ac17fc
--- /dev/null
+++ b/data/ui/PlaylistsView.ui
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="PlaylistsView" parent="GtkPaned">
+ <property name="shrink-start-child">0</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="width-request">220</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="scroll-to-focus">True</property>
+ <child>
+ <object class="GtkListBox" id="_sidebar">
+ <property name="selection-mode">single</property>
+ <signal name="row-activated" handler="_on_playlist_activated" swapped="no"/>
+ <style>
+ <class name="navigation-sidebar"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/PlaylistsWidget.ui b/data/ui/PlaylistsWidget.ui
new file mode 100644
index 00000000..7a9e3cfb
--- /dev/null
+++ b/data/ui/PlaylistsWidget.ui
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="PlaylistsWidget" parent="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="AdwClamp">
+ <property name="maximum-size">1000</property>
+ <child>
+ <object class="PlaylistControls" id="_pl_ctrls">
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="playlist-container">
+ <property name="vexpand">True</property>
+ <child>
+ <object class="AdwClamp">
+ <property name="maximum-size">1000</property>
+ <property name="valign">start</property>
+ <child>
+ <object class="GtkListBox" id="_songs_list">
+ <property name="margin-bottom">20</property>
+ <property name="margin-top">20</property>
+ <signal name="row-activated" handler="_on_song_activated" swapped="no"/>
+ <style>
+ <class name="boxed-list"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/SearchHeaderBar.ui b/data/ui/SearchHeaderBar.ui
new file mode 100644
index 00000000..d8dec507
--- /dev/null
+++ b/data/ui/SearchHeaderBar.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="SearchHeaderBar" parent="AdwBin">
+ <child>
+ <object class="AdwHeaderBar" id="_headerbar">
+ <property name="vexpand">False</property>
+ <style>
+ <class name="titlebar"/>
+ </style>
+ <child type="end">
+ <object class="GtkToggleButton" id="_select_button">
+ <property name="valign">center</property>
+ <property name="sensitive">True</property>
+ <property name="icon-name">selection-mode-symbolic</property>
+ <property name="tooltip_text" translatable="yes">Select</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkButton" id="_cancel_button">
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="use_underline">True</property>
+ <property name="valign">center</property>
+ <property name="sensitive">True</property>
+ <signal name="clicked" handler="_on_cancel_button_clicked" swapped="no"/>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkToggleButton" id="_search_button">
+ <property name="valign">center</property>
+ <property name="sensitive">True</property>
+ <property name="icon-name">edit-find-symbolic</property>
+ <property name="tooltip_text" translatable="yes">Search</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkSizeGroup" id="size1">
+ <property name="mode">vertical</property>
+ <widgets>
+ <widget name="_search_button"/>
+ <widget name="_cancel_button"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/data/ui/SearchView.ui b/data/ui/SearchView.ui
new file mode 100644
index 00000000..8a2af34b
--- /dev/null
+++ b/data/ui/SearchView.ui
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="SearchView" parent="GtkStack">
+ <child>
+ <object class="GtkScrolledWindow" id="_search_results">
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="scroll-to-focus">True</property>
+ <child>
+ <object class="AdwClamp">
+ <property name="maximum-size">1600</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="margin-bottom">20</property>
+ <property name="margin-end">120</property>
+ <property name="margin-start">120</property>
+ <property name="margin-top">20</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="_artist_header">
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="homogeneous">True</property>
+ <property name="orientation">horizontal</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Artists</property>
+ <style>
+ <class name="search-header"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="_view_all_artists">
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">View All</property>
+ <property name="icon-name">go-next-symbolic</property>
+ <signal name="clicked" handler="_on_all_artists_clicked" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFlowBox" id="_artist_flowbox">
+ <property name="column_spacing">6</property>
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="homogeneous">True</property>
+ <property name="margin-bottom">18</property>
+ <property name="margin-top">18</property>
+ <property name="max-children-per-line">6</property>
+ <property name="min-children-per-line">1</property>
+ <property name="row_spacing">12</property>
+ <property name="selection-mode">none</property>
+ <property name="valign">start</property>
+ <signal name="child-activated" handler="_on_artist_activated" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="_album_header">
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="homogeneous">True</property>
+ <property name="orientation">horizontal</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Albums</property>
+ <style>
+ <class name="search-header"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="_view_all_albums">
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">View All</property>
+ <property name="icon_name">go-next-symbolic</property>
+ <signal name="clicked" handler="_on_all_albums_clicked" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFlowBox" id="_album_flowbox">
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="valign">start</property>
+ <property name="homogeneous">True</property>
+ <property name="min_children_per_line">1</property>
+ <property name="max_children_per_line">6</property>
+ <property name="margin-bottom">18</property>
+ <property name="margin-top">18</property>
+ <property name="row_spacing">12</property>
+ <property name="column_spacing">6</property>
+ <property name="selection_mode">none</property>
+ <signal name="child-activated" handler="_on_album_activated" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="_songs_header">
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="homogeneous">True</property>
+ <property name="orientation">horizontal</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Songs</property>
+ <style>
+ <class name="search-header"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="_songs_listbox">
+ <property name="margin-top">20</property>
+ <signal name="row-activated" handler="_song_activated" swapped="no"/>
+ <style>
+ <class name="boxed-list"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="_all_search_results">
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="scroll-to-focus">True</property>
+ <child>
+ <object class="AdwClamp">
+ <property name="maximum-size">1600</property>
+ <child>
+ <object class="GtkBox">
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="margin-bottom">20</property>
+ <property name="margin-end">120</property>
+ <property name="margin-start">120</property>
+ <property name="margin-top">20</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkFlowBox" id="_artist_all_flowbox">
+ <property name="column_spacing">6</property>
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="homogeneous">True</property>
+ <property name="margin-bottom">18</property>
+ <property name="margin-top">18</property>
+ <property name="max-children-per-line">6</property>
+ <property name="min-children-per-line">1</property>
+ <property name="row_spacing">12</property>
+ <property name="selection-mode">none</property>
+ <property name="valign">start</property>
+ <signal name="child-activated" handler="_on_artist_activated" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFlowBox" id="_album_all_flowbox">
+ <property name="halign">fill</property>
+ <property name="hexpand">True</property>
+ <property name="valign">start</property>
+ <property name="homogeneous">True</property>
+ <property name="min_children_per_line">1</property>
+ <property name="max_children_per_line">6</property>
+ <property name="margin-bottom">18</property>
+ <property name="margin-top">18</property>
+ <property name="row_spacing">12</property>
+ <property name="column_spacing">6</property>
+ <property name="selection_mode">none</property>
+ <signal name="child-activated" handler="_on_album_activated" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="_scrolled_album_widget">
+ <property name="hscrollbar_policy">never</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="scroll-to-focus">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/SelectionBarMenuButton.ui b/data/ui/SelectionBarMenuButton.ui
new file mode 100644
index 00000000..6787651b
--- /dev/null
+++ b/data/ui/SelectionBarMenuButton.ui
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.4"/>
+ <menu id="selection-menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">Select All</attribute>
+ <attribute name="action">win.select_all</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Select None</attribute>
+ <attribute name="action">win.deselect_all</attribute>
+ </item>
+ </section>
+ </menu>
+ <template class="SelectionBarMenuButton" parent="GtkMenuButton">
+ <property name="always-show-arrow">True</property>
+ <property name="focusable">True</property>
+ <property name="label" translatable="yes">Click on items to select them</property>
+ <property name="menu-model">selection-menu</property>
+ </template>
+</interface>
diff --git a/data/ui/SelectionToolbar.ui b/data/ui/SelectionToolbar.ui
new file mode 100644
index 00000000..852b7367
--- /dev/null
+++ b/data/ui/SelectionToolbar.ui
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="SelectionToolbar" parent="GtkActionBar">
+ <property name="visible">False</property>
+ <property name="focusable">False</property>
+ <child>
+ <object class="GtkButton" id="_add_to_playlist_button">
+ <property name="label" translatable="yes">_Add to Playlist</property>
+ <property name="use_underline">True</property>
+ <property name="focusable">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="_on_add_to_playlist_button_clicked" swapped="no"/>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/SongListItem.ui b/data/ui/SongListItem.ui
new file mode 100644
index 00000000..3d906d61
--- /dev/null
+++ b/data/ui/SongListItem.ui
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="4.0"/>
+ <object class="GtkBox" id="_song_box">
+ <property name="focusable">False</property>
+ <property name="valign">start</property>
+ <child>
+ <object class="GtkCheckButton" id="_check">
+ <property name="visible">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkLabel" id="_title_label">
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="ellipsize">end</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_album_label">
+ <property name="ellipsize">end</property>
+ <property name="halign">start</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_artist_label">
+ <property name="ellipsize">end</property>
+ <property name="halign">start</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_duration_label">
+ <property name="halign">start</property>
+ <property name="single_line_mode">True</property>
+ <property name="width_chars">5</property>
+ <property name="xalign">1.0</property>
+ <attributes>
+ <attribute name="font-features" value="tnum=1"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="_star_box">
+ <property name="focusable">0</property>
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="StarImage" id="_star_image">
+ <property name="focusable">False</property>
+ <property name="valign">center</property>
+ <property name="margin-end">12</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="_menu_button">
+ <property name="focusable">True</property>
+ <property name="icon-name">view-more-symbolic</property>
+ <style>
+ <class name="flat"/>
+ </style>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/data/ui/SongWidget.ui b/data/ui/SongWidget.ui
new file mode 100644
index 00000000..050f3b08
--- /dev/null
+++ b/data/ui/SongWidget.ui
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template class="SongWidget" parent="GtkListBoxRow">
+ <property name="selectable">False</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="focusable">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="_dnd_icon">
+ <property name="visible">False</property>
+ <property name="icon-name">list-drag-handle-symbolic</property>
+ <style>
+ <class name="drag-handle"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="width_request">48</property>
+ <property name="focusable">False</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkImage" id="_play_icon">
+ <property name="focusable">False</property>
+ <property name="icon_size">1</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="_select_button">
+ <property name="focusable">False</property>
+ <property name="receives_default">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_number_label">
+ <property name="focusable">False</property>
+ <property name="halign">end</property>
+ <property name="justify">right</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="title_box">
+ <property name="focusable">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkLabel" id="_title_label">
+ <property name="focusable">False</property>
+ <property name="xalign">0</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="ellipsize">end</property>
+ <property name="max_width_chars">90</property>
+ <property name="justify">fill</property>
+ <property name="margin-start">9</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="_artist_box">
+ <property name="visible">False</property>
+ <property name="focusable">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkLabel" id="_artist_label">
+ <property name="focusable">False</property>
+ <property name="xalign">0</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="ellipsize">end</property>
+ <property name="max_width_chars">90</property>
+ <property name="justify">fill</property>
+ <property name="margin-start">9</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="_album_duration_box">
+ <property name="focusable">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="_album_label">
+ <property name="visible">False</property>
+ <property name="focusable">False</property>
+ <property name="xalign">0</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="ellipsize">end</property>
+ <property name="max_width_chars">90</property>
+ <property name="justify">fill</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_duration_label">
+ <property name="focusable">False</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="single_line_mode">True</property>
+ <attributes>
+ <attribute name="font-features" value="tnum=1"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="_star_stack">
+ <property name="focusable">False</property>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">star</property>
+ <property name="child">
+ <object class="GtkBox" id="_star_box">
+ <property name="focusable">0</property>
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkGestureClick">
+ <property name="button">1</property>
+ <property name="propagation-phase">capture</property>
+ <signal name="released" handler="_on_star_toggle" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkEventControllerMotion">
+ <signal name="enter" handler="_on_star_hover" swapped="no"/>
+ <signal name="leave" handler="_on_star_unhover" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="StarImage" id="_star_image">
+ <property name="focusable">False</property>
+ <property name="valign">center</property>
+ <property name="margin-end">12</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">empty</property>
+ <property name="child">
+ <object class="GtkBox"/>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="_menu_button">
+ <property name="visible">False</property>
+ <property name="focusable">True</property>
+ <property name="icon-name">view-more-symbolic</property>
+ <style>
+ <class name="flat"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkGestureClick">
+ <property name="button">1</property>
+ <signal name="released" handler="_on_click" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkDragSource" id="_drag_source">
+ <property name="actions">move</property>
+ <property name="propagation-phase">none</property>
+ <signal name="prepare" handler="_on_drag_prepare" swapped="no"/>
+ <signal name="drag-begin" handler="_on_drag_begin" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkDropTarget">
+ <property name="actions">move</property>
+ <property name="formats">SongWidget</property>
+ <property name="preload">True</property>
+ <signal name="drop" handler="_on_drop" swapped="no"/>
+ </object>
+ </child>
+ <style>
+ <class name="songwidget"/>
+ </style>
+ </template>
+ <object class="GtkSizeGroup" id="_size_group">
+ <property name="mode">horizontal</property>
+ <widgets>
+ <widget name="title_box"/>
+ <widget name="_artist_box"/>
+ <widget name="_album_duration_box"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/data/ui/SongWidgetMenu.ui b/data/ui/SongWidgetMenu.ui
new file mode 100644
index 00000000..17c7a34a
--- /dev/null
+++ b/data/ui/SongWidgetMenu.ui
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="SongWidgetMenu" parent="GtkPopoverMenu">
+ <property name="autohide">True</property>
+ <property name="position">bottom</property>
+ <property name="visible">False</property>
+ <property name="menu-model">song-menu</property>
+ </template>
+ <menu id="song-menu">
+ <item>
+ <attribute name="label" translatable="yes">_Play</attribute>
+ <attribute name="action">songwidget.play</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Add to Playlist…</attribute>
+ <attribute name="action">songwidget.add_playlist</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Remove from Playlist</attribute>
+ <attribute name="action">songwidget.remove_playlist</attribute>
+ </item>
+ </menu>
+</interface>
diff --git a/data/ui/SongsView.ui b/data/ui/SongsView.ui
new file mode 100644
index 00000000..c2dc2126
--- /dev/null
+++ b/data/ui/SongsView.ui
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template class="SongsView" parent="GtkBox">
+ <property name="margin-bottom">48</property>
+ <property name="margin-top">48</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <child>
+ <object class="AdwClampScrollable" id="_adw_clamp_scrollable">
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="maximum-size">1000</property>
+ <child>
+ <object class="GtkListView" id="_listview">
+ <property name="show-separators">True</property>
+ <style>
+ <class name="songs-list"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/TwoLineTip.ui b/data/ui/TwoLineTip.ui
new file mode 100644
index 00000000..2ebece59
--- /dev/null
+++ b/data/ui/TwoLineTip.ui
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="TwoLineTip" parent="GtkBox">
+ <property name="focusable">False</property>
+ <property name="vexpand">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="_title_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ <style>
+ <class name="tooltip-title"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_subtitle_label">
+ <property name="focusable">False</property>
+ <property name="halign">start</property>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/Window.ui b/data/ui/Window.ui
new file mode 100644
index 00000000..9c9b80bc
--- /dev/null
+++ b/data/ui/Window.ui
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="Window" parent="AdwApplicationWindow">
+ <property name="default-height">500</property>
+ <property name="default-width">300</property>
+ <child>
+ <object class="GtkEventControllerKey">
+ <property name="propagation-phase">capture</property>
+ <signal name="key-pressed" handler="_on_key_press" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="AdwToastOverlay" id="_toast_overlay">
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStack" id="_headerbar_stack">
+ <property name="transition-type">crossfade</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkOverlay" id="_overlay">
+ <property name="vexpand">True</property>
+ <child>
+ <object class="AdwViewStack" id="_stack">
+ <property name="focusable">False</property>
+ <property name="hhomogeneous">False</property>
+ <property name="vhomogeneous">False</property>
+ </object>
+ </child>
+ <child type="overlay">
+ <object class="GtkProgressBar" id="_loading_progress">
+ <property name="valign">start</property>
+ <property name="visible">False</property>
+ <style>
+ <class name="osd"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="SelectionToolbar" id="_selection_toolbar"/>
+ </child>
+ <child>
+ <object class="PlayerToolbar" id="_player_toolbar"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/help-overlay.ui b/data/ui/help-overlay.ui
new file mode 100644
index 00000000..809063b7
--- /dev/null
+++ b/data/ui/help-overlay.ui
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <object class="GtkShortcutsWindow" id="help_overlay">
+ <property name="modal">True</property>
+ <child>
+ <object class="GtkShortcutsSection">
+ <property name="section-name">shortcuts</property>
+ <property name="max-height">17</property>
+ <child>
+ <object class="GtkShortcutsGroup">
+ <property name="title" translatable="yes" context="shortcut window">General</property>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Close window</property>
+ <property name="action-name">app.quit</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Search</property>
+ <property name="accelerator">&lt;Primary&gt;F</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Help</property>
+ <property name="action-name">app.help</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Shortcuts</property>
+ <property name="action-name">win.show-help-overlay</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsGroup">
+ <property name="title" translatable="yes" context="shortcut window">Playback</property>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Play/Pause</property>
+ <property name="accelerator">&lt;Ctrl&gt;space</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Next song</property>
+ <property name="accelerator">&lt;Ctrl&gt;N</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Previous song</property>
+ <property name="accelerator">&lt;Ctrl&gt;B</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Toggle repeat</property>
+ <property name="accelerator">&lt;Ctrl&gt;R</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Toggle shuffle</property>
+ <property name="accelerator">&lt;Ctrl&gt;S</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsGroup">
+ <property name="title" translatable="yes" context="shortcut window">Navigation</property>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Go to Albums</property>
+ <property name="accelerator">&lt;Alt&gt;1</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Go to Artists</property>
+ <property name="accelerator">&lt;Alt&gt;2</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Go to Songs</property>
+ <property name="accelerator">&lt;Alt&gt;3</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Go to Playlists</property>
+ <property name="accelerator">&lt;Alt&gt;4</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="title" translatable="yes" context="shortcut window">Go back</property>
+ <property name="accelerator">&lt;Alt&gt;Left</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>