[gnome-music/bilelmoussaoui/adaptive-ui] WIP: make Music UI adaptive



commit 94c4d2e09ad07686c8693a41a9f27c96dc2126f4
Author: Bilal Elmoussaoui <bil elmoussaoui gmail com>
Date:   Tue Sep 17 03:34:40 2019 +0200

    WIP: make Music UI adaptive

 data/ui/AlbumWidget.ui                   | 403 +++++++++++-----------
 data/ui/AlbumsView.ui                    |   8 +-
 data/ui/ArtistAlbumWidget.ui             | 126 ++++---
 data/ui/HeaderBar.ui                     | 173 +++++++---
 data/ui/PlayerToolbar.ui                 | 551 ++++++++++++++++---------------
 data/ui/Window.ui                        |  54 ++-
 gnome-music.in                           |   5 +-
 gnomemusic/utils.py                      |   6 +
 gnomemusic/views/albumsview.py           |  20 +-
 gnomemusic/views/artistsview.py          |  19 +-
 gnomemusic/views/baseview.py             |  34 +-
 gnomemusic/views/playlistsview.py        |  54 ++-
 gnomemusic/views/songsview.py            |   2 +-
 gnomemusic/widgets/albumwidget.py        |  18 +
 gnomemusic/widgets/artistalbumswidget.py |   7 +
 gnomemusic/widgets/artistalbumwidget.py  |  20 +-
 gnomemusic/widgets/headerbar.py          |  64 +++-
 gnomemusic/widgets/playertoolbar.py      |  32 +-
 gnomemusic/widgets/searchheaderbar.py    |   2 +-
 gnomemusic/window.py                     |  57 +++-
 meson.build                              |   2 +
 org.gnome.Music.json                     |  14 +
 22 files changed, 1050 insertions(+), 621 deletions(-)
---
diff --git a/data/ui/AlbumWidget.ui b/data/ui/AlbumWidget.ui
index 7f6b770d..3206d732 100644
--- a/data/ui/AlbumWidget.ui
+++ b/data/ui/AlbumWidget.ui
@@ -1,242 +1,273 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.20.0 -->
+<!-- Generated with glade 3.22.1 -->
 <interface>
   <requires lib="gtk+" version="3.12"/>
+  <requires lib="libhandy" version="0.0"/>
   <template class="AlbumWidget" parent="GtkEventBox">
     <property name="visible">True</property>
-    <style>
-      <class name="view"/>
-      <class name="content-view"/>
-    </style>
+    <property name="can_focus">False</property>
     <child>
-      <object class="GtkBox">
+      <object class="GtkScrolledWindow">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+        <property name="hscrollbar_policy">never</property>
         <child>
-          <object class="GtkBox" id="albumInfo">
+          <object class="GtkViewport">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="halign">end</property>
-            <property name="margin_start">32</property>
-            <property name="margin_end">32</property>
-            <property name="margin_top">64</property>
-            <property name="margin_bottom">32</property>
-            <property name="vexpand">True</property>
             <property name="hexpand">True</property>
+            <property name="shadow_type">none</property>
             <child>
-              <object class="GtkBox" id="albumDetails">
+              <object class="GtkBox" id="_album_widget">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="halign">center</property>
-                <property name="valign">start</property>
-                <property name="orientation">vertical</property>
-                <property name="spacing">18</property>
-                <child>
-                  <object class="CoverStack" id="_cover_stack">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="halign">center</property>
-                    <property name="valign">start</property>
-                    <property name="margin_start">1</property>
-                    <property name="margin_end">1</property>
-                  </object>
-                  <packing>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
+                <property name="spacing">6</property>
                 <child>
-                  <object class="GtkBox" id="artistBox">
+                  <object class="GtkBox" id="_album_info">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="halign">center</property>
                     <property name="valign">start</property>
-                    <property name="orientation">vertical</property>
-                    <property name="spacing">3</property>
+                    <property name="hexpand">True</property>
                     <child>
-                      <object class="GtkLabel" id="_title_label">
+                      <object class="GtkBox" id="albumDetails">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="halign">center</property>
-                        <property name="justify">center</property>
-                        <property name="ellipsize">middle</property>
-                        <style>
-                          <class name="title-artist"/>
-                        </style>
+                        <property name="valign">start</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">18</property>
+                        <child>
+                          <object class="CoverStack" id="_cover_stack">
+                                   <property name="visible">True</property>
+                                   <property name="can_focus">False</property>
+                                   <property name="halign">center</property>
+                                   <property name="valign">start</property>
+                                   <property name="margin_start">1</property>
+                                   <property name="margin_end">1</property>
+                                 </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkBox" id="artistBox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="halign">center</property>
+                            <property name="valign">start</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">3</property>
+                            <child>
+                              <object class="GtkLabel" id="_title_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">center</property>
+                                <property name="justify">center</property>
+                                <property name="ellipsize">middle</property>
+                                <style>
+                                  <class name="title-artist"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_artist_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">center</property>
+                                <property name="justify">center</property>
+                                <property name="ellipsize">middle</property>
+                                <style>
+                                  <class name="title-artist"/>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkGrid" id="grid">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="column_spacing">32</property>
+                            <property name="column_homogeneous">True</property>
+                            <child>
+                              <object class="GtkLabel" id="released_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">end</property>
+                                <property name="margin_top">2</property>
+                                <property name="margin_bottom">2</property>
+                                <property name="label" translatable="yes">Released</property>
+                                <property name="use_markup">True</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="running_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">end</property>
+                                <property name="label" translatable="yes">Running Length</property>
+                                <property name="use_markup">True</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_released_info_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="margin_top">2</property>
+                                <property name="margin_bottom">2</property>
+                                <property name="label">----</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="top_attach">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_running_info_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="label">--:--</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="top_attach">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_composer_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="no_show_all">True</property>
+                                <property name="halign">end</property>
+                                <property name="margin_top">2</property>
+                                <property name="margin_bottom">2</property>
+                                <property name="label" translatable="yes">Composer</property>
+                                <property name="use_markup">True</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">2</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_composer_info_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="no_show_all">True</property>
+                                <property name="halign">start</property>
+                                <property name="margin_top">2</property>
+                                <property name="margin_bottom">2</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="top_attach">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">3</property>
+                          </packing>
+                        </child>
                       </object>
                       <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
-                    <child>
-                      <object class="GtkLabel" id="_artist_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="halign">center</property>
-                        <property name="justify">center</property>
-                        <property name="ellipsize">middle</property>
-                        <style>
-                          <class name="title-artist"/>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
                   </object>
                   <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkGrid" id="grid">
+                  <object class="GtkBox">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="margin_top">21</property>
-                    <property name="column_spacing">32</property>
-                    <property name="column_homogeneous">True</property>
-                    <child>
-                      <object class="GtkLabel" id="released_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="halign">end</property>
-                        <property name="margin_top">2</property>
-                        <property name="margin_bottom">2</property>
-                        <property name="label" translatable="yes">Released</property>
-                        <property name="use_markup">True</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="running_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="halign">end</property>
-                        <property name="label" translatable="yes">Running Length</property>
-                        <property name="use_markup">True</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="_released_info_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="halign">start</property>
-                        <property name="margin_top">2</property>
-                        <property name="margin_bottom">2</property>
-                        <property name="label">----</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="_running_info_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="halign">start</property>
-                        <property name="label">--:--</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="_composer_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="no_show_all">True</property>
-                        <property name="halign">end</property>
-                        <property name="margin_top">2</property>
-                        <property name="margin_bottom">2</property>
-                        <property name="label" translatable="yes">Composer</property>
-                        <property name="use_markup">True</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">2</property>
-                      </packing>
-                    </child>
+                    <property name="valign">start</property>
                     <child>
-                      <object class="GtkLabel" id="_composer_info_label">
+                      <object class="HdyColumn">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="no_show_all">True</property>
-                        <property name="halign">start</property>
-                        <property name="margin_top">2</property>
-                        <property name="margin_bottom">2</property>
-                        <property name="ellipsize">end</property>
+                        <property name="hexpand">True</property>
+                        <property name="maximum_width">800</property>
+                        <property name="linear_growth_width">800</property>
+                        <child>
+                          <object class="DiscListBox" id="_listbox">
+                                  <property name="can_focus">False</property>
+                                  <property name="selection_mode">0</property>
+                                  <property name="halign">fill</property>
+                                  <property name="visible">True</property>
+                              </object>
+                        </child>
                       </object>
                       <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">2</property>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
-                    <property name="position">3</property>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
                   </packing>
                 </child>
               </object>
-              <packing>
-                <property name="position">0</property>
-              </packing>
             </child>
           </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkScrolledWindow" id="scrolledWindow">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="hexpand">True</property>
-            <property name="vexpand">True</property>
-            <property name="hscrollbar_policy">never</property>
-            <child>
-              <object class="GtkViewport" id="_viewport">
-                <property name="width_request">600</property>
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">start</property>
-                <property name="hexpand">True</property>
-                <property name="shadow_type">none</property>
-                <child>
-                  <object class="DiscListBox" id="_listbox">
-                    <property name="can_focus">False</property>
-                    <property name="margin_top">64</property>
-                    <property name="margin_bottom">64</property>
-                    <property name="margin_end">32</property>
-                    <property name="selection_mode">0</property>
-                    <property name="visible">True</property>
-                  </object>
-                </child>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="position">2</property>
-          </packing>
         </child>
       </object>
     </child>
+    <style>
+      <class name="view"/>
+      <class name="content-view"/>
+    </style>
   </template>
 </interface>
diff --git a/data/ui/AlbumsView.ui b/data/ui/AlbumsView.ui
index 116231fe..30ae439d 100644
--- a/data/ui/AlbumsView.ui
+++ b/data/ui/AlbumsView.ui
@@ -10,11 +10,11 @@
             <property name="column_spacing">6</property>
             <property name="halign">fill</property>
             <property name="hexpand">True</property>
-            <property name="homogeneous">True</property>
-            <property name="margin">18</property>
-            <property name="max-children-per-line">20</property>
+            <property name="margin-top">18</property>
+            <property name="margin-bottom">18</property>
+            <property name="max-children-per-line">10</property>
             <property name="min-children-per-line">1</property>
-            <property name="row_spacing">12</property>
+            <property name="row_spacing">6</property>
             <property name="selection-mode">none</property>
             <property name="valign">start</property>
             <property name="visible">True</property>
diff --git a/data/ui/ArtistAlbumWidget.ui b/data/ui/ArtistAlbumWidget.ui
index 54ccb83f..4d9690d4 100644
--- a/data/ui/ArtistAlbumWidget.ui
+++ b/data/ui/ArtistAlbumWidget.ui
@@ -1,68 +1,84 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.20.0 -->
+<!-- Generated with glade 3.22.1 -->
 <interface>
   <requires lib="gtk+" version="3.12"/>
-  <template parent="GtkBox" class="ArtistAlbumWidget">
-    <property name="margin_top">30</property>
-    <property name="margin_right">120</property>
+  <template class="ArtistAlbumWidget" parent="HdyColumn">
     <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="hexpand">True</property>
+    <property name="maximum_width">800</property>
+    <property name="margin_top">32</property>
+    <property name="linear_growth_width">800</property>
     <child>
-      <object class="CoverStack" id="_cover_stack">
-        <property name="visible">True</property>
-       <property name="margin_top">20</property>
-       <property name="margin_right">30</property>
-        <property name="margin_bottom">20</property>
-       <property name="margin_left">120</property>
-        <property name="can_focus">False</property>
-        <property name="valign">start</property>
-      </object>
-      <packing>
-        <property name="position">0</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkBox" id="_album_box">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkBox" id="box3">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
+        <object class="GtkBox">
+          <property name="visible">True</property>
+          <property name="can_focus">False</property>
+          <property name="orientation">vertical</property>
+            <child>
+              <object class="CoverStack" id="_cover_stack">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="valign">center</property>
+                <property name="halign">center</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
             <child>
-              <object class="GtkLabel" id="_title_year">
+              <object class="GtkBox" id="_album_box">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="margin_top">20</property>
-                <property name="margin_bottom">20</property>
-                <property name="ellipsize">middle</property>
-                <property name="xalign">0</property>
-                <property name="yalign">0</property>
-                <style>
-                  <class name="album-title"/>
-                </style>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkBox" id="box3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkLabel" id="_title_year">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="margin_top">20</property>
+                        <property name="margin_bottom">20</property>
+                        <property name="ellipsize">middle</property>
+                        <property name="xalign">0</property>
+                        <property name="yalign">0</property>
+                        <property name="halign">center</property>
+                        <style>
+                          <class name="album-title"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="DiscListBox" id="_disc_list_box">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="selection-mode">0</property>
+                    <!-- <property name="orientation">vertical</property> -->
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
               </object>
             </child>
-          </object>
-          <packing>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="DiscListBox" id="_disc_list_box">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="selection-mode">0</property>
-            <!-- <property name="orientation">vertical</property> -->
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="position">1</property>
-      </packing>
+        </object>
     </child>
   </template>
 </interface>
diff --git a/data/ui/HeaderBar.ui b/data/ui/HeaderBar.ui
index bf04a328..8bed3be6 100644
--- a/data/ui/HeaderBar.ui
+++ b/data/ui/HeaderBar.ui
@@ -1,64 +1,141 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
 <interface>
-  <!-- interface-requires gtk+ 3.10 -->
+  <requires lib="gtk+" version="3.20"/>
+  <requires lib="libhandy" version="0.0"/>
   <template class="HeaderBar" parent="GtkHeaderBar">
     <property name="visible">True</property>
-    <property name="vexpand">False</property>
+    <property name="can_focus">False</property>
+    <property name="hexpand">True</property>
+    <property name="show_close_button">True</property>
     <child>
-      <object class="GtkMenuButton" id="_menu_button">
+      <object class="GtkButton" id="_back_button">
         <property name="visible">True</property>
-        <property name="can_focus">False</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="tooltip_text" translatable="yes">Back</property>
         <property name="valign">center</property>
-        <property name="sensitive">True</property>
-        <property name="tooltip_text" translatable="yes">Menu</property>
+        <signal name="clicked" handler="_on_back_button_clicked" swapped="no"/>
+        <child>
+          <object class="GtkImage" id="_back_button_image">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="icon_name">go-previous-symbolic</property>
+            <property name="icon_size">1</property>
+          </object>
+        </child>
         <style>
           <class name="image-button"/>
         </style>
-        <child>
-          <object class="GtkImage" id="_menu_button_image">
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <child type="center">
+          <object class="HdySqueezer" id="_squeezer">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="icon-name">open-menu-symbolic</property>
-            <property name="icon-size">1</property>
+            <property name="transition_type">crossfade</property>
+            <child>
+              <object class="HdyViewSwitcher" id="_title_wide_switcher">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">center</property>
+                <property name="policy">wide</property>
+              </object>
+            </child>
+            <child>
+              <object class="HdyViewSwitcher" id="_title_narrow_switcher">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">center</property>
+                <property name="policy">narrow</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkBox" id="_title_text">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">center</property>
+                <property name="valign">center</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="_title_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Music</property>
+                    <style>
+                      <class name="title"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="_subtitle_label">
+                    <property name="can_focus">False</property>
+                    <style>
+                      <class name="subtitle"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
           </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
         </child>
       </object>
       <packing>
-        <property name="pack_type">end</property>
+        <property name="position">1</property>
       </packing>
     </child>
     <child>
       <object class="GtkToggleButton" id="_select_button">
         <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="valign">center</property>
-        <property name="sensitive">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
         <property name="tooltip_text" translatable="yes">Select</property>
-        <style>
-          <class name="image-button"/>
-        </style>
+        <property name="valign">center</property>
         <child>
           <object class="GtkImage" id="_select_button_image">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="icon-name">object-select-symbolic</property>
-            <property name="icon-size">1</property>
+            <property name="icon_name">object-select-symbolic</property>
+            <property name="icon_size">1</property>
           </object>
         </child>
+        <style>
+          <class name="image-button"/>
+        </style>
       </object>
       <packing>
         <property name="pack_type">end</property>
+        <property name="position">2</property>
       </packing>
     </child>
     <child>
       <object class="GtkButton" id="_cancel_button">
-        <property name="visible">False</property>
-        <property name="no_show_all">True</property>
-        <property name="can_focus">False</property>
         <property name="label" translatable="yes">_Cancel</property>
-        <property name="use_underline">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="no_show_all">True</property>
         <property name="valign">center</property>
-        <property name="sensitive">True</property>
+        <property name="use_underline">True</property>
         <signal name="clicked" handler="_on_cancel_button_clicked" swapped="no"/>
         <style>
           <class name="text-button"/>
@@ -66,61 +143,59 @@
       </object>
       <packing>
         <property name="pack_type">end</property>
+        <property name="position">3</property>
       </packing>
     </child>
     <child>
       <object class="GtkToggleButton" id="_search_button">
         <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="valign">center</property>
-        <property name="sensitive">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
         <property name="tooltip_text" translatable="yes">Search</property>
-        <style>
-          <class name="image-button"/>
-        </style>
+        <property name="valign">center</property>
         <child>
           <object class="GtkImage" id="_search_button_image">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="icon-name">edit-find-symbolic</property>
-            <property name="icon-size">1</property>
+            <property name="icon_name">edit-find-symbolic</property>
+            <property name="icon_size">1</property>
           </object>
         </child>
+        <style>
+          <class name="image-button"/>
+        </style>
       </object>
       <packing>
         <property name="pack_type">end</property>
+        <property name="position">4</property>
       </packing>
     </child>
     <child>
-      <object class="GtkButton" id="_back_button">
+      <object class="GtkMenuButton" id="_menu_button">
         <property name="visible">True</property>
-        <property name="can_focus">False</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="tooltip_text" translatable="yes">Menu</property>
         <property name="valign">center</property>
-        <property name="sensitive">True</property>
-        <property name="tooltip_text" translatable="yes">Back</property>
-        <signal name="clicked" handler="_on_back_button_clicked" swapped="no"/>
-        <style>
-              <class name="image-button"/>
-        </style>
         <child>
-          <object class="GtkImage" id="_back_button_image">
+          <object class="GtkImage" id="_menu_button_image">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="icon-name">go-previous-symbolic</property>
-            <property name="icon-size">1</property>
+            <property name="icon_name">open-menu-symbolic</property>
+            <property name="icon_size">1</property>
           </object>
         </child>
+        <style>
+          <class name="image-button"/>
+        </style>
       </object>
       <packing>
-        <property name="pack_type">start</property>
+        <property name="pack_type">end</property>
+        <property name="position">1</property>
       </packing>
     </child>
   </template>
   <object class="GtkSizeGroup" id="size1">
-      <property name="mode">vertical</property>
-      <widgets>
-        <widget name="_search_button"/>
-        <widget name="_cancel_button"/>
-      </widgets>
+    <property name="mode">vertical</property>
   </object>
 </interface>
diff --git a/data/ui/PlayerToolbar.ui b/data/ui/PlayerToolbar.ui
index 3eebcf6e..9c03937f 100644
--- a/data/ui/PlayerToolbar.ui
+++ b/data/ui/PlayerToolbar.ui
@@ -1,47 +1,26 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
 <interface>
   <requires lib="gtk+" version="3.12"/>
-  <menu id="repeatMenu">
-    <item>
-      <attribute name="label" translatable="yes">Shuffle</attribute>
-      <attribute name="action">win.repeat</attribute>
-      <attribute name="target">shuffle</attribute>
-    </item>
-    <item>
-      <attribute name="label" translatable="yes">Repeat All</attribute>
-      <attribute name="action">win.repeat</attribute>
-      <attribute name="target">all</attribute>
-    </item>
-    <item>
-      <attribute name="label" translatable="yes">Repeat Song</attribute>
-      <attribute name="action">win.repeat</attribute>
-      <attribute name="target">song</attribute>
-    </item>
-    <item>
-      <attribute name="label" translatable="yes" comments="Causes tracks to play in random 
order">Shuffle/Repeat Off</attribute>
-      <attribute name="action">win.repeat</attribute>
-      <attribute name="target">none</attribute>
-    </item>
-  </menu>
-  <object class="GtkImage" id="next_image">
+  <object class="GtkImage" id="_pause_image">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="margin_top">1</property>
-    <property name="icon_name">media-skip-forward-symbolic</property>
+    <property name="icon_name">media-playback-pause-symbolic</property>
     <property name="icon_size">1</property>
   </object>
-  <object class="GtkImage" id="_pause_image">
+  <object class="GtkImage" id="_play_image">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="margin_top">1</property>
-    <property name="icon_name">media-playback-pause-symbolic</property>
+    <property name="icon_name">media-playback-start-symbolic</property>
     <property name="icon_size">1</property>
   </object>
-  <object class="GtkImage" id="_play_image">
+  <object class="GtkImage" id="next_image">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="margin_top">1</property>
-    <property name="icon_name">media-playback-start-symbolic</property>
+    <property name="icon_name">media-skip-forward-symbolic</property>
     <property name="icon_size">1</property>
   </object>
   <object class="GtkImage" id="previous_image">
@@ -52,240 +31,288 @@
     <property name="icon_size">1</property>
   </object>
   <template class="PlayerToolbar" parent="GtkActionBar">
-    <property name="can_focus">False</property>
-    <property name="no_show_all">True</property>
-    <child>
-      <object class="GtkBox" id="buttons">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <child>
-          <object class="GtkButton" id="_prev_button">
-            <property name="width_request">42</property>
-            <property name="visible">True</property>
-            <property name="sensitive">False</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="image">previous_image</property>
-            <property name="always_show_image">True</property>
-            <property name="tooltip_text" translatable="yes">Previous</property>
-            <signal name="clicked" handler="_on_prev_button_clicked" swapped="no"/>
-          </object>
-          <packing>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkButton" id="_play_button">
-            <property name="width_request">60</property>
-            <property name="visible">True</property>
-            <property name="sensitive">False</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="image">_play_image</property>
-            <property name="always_show_image">True</property>
-            <property name="tooltip_text" translatable="yes">Play</property>
-            <signal name="clicked" handler="_on_play_button_clicked" swapped="no"/>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkButton" id="_next_button">
-            <property name="width_request">42</property>
-            <property name="visible">True</property>
-            <property name="sensitive">False</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="image">next_image</property>
-            <property name="always_show_image">True</property>
-            <property name="tooltip_text" translatable="yes">Next</property>
-            <signal name="clicked" handler="_on_next_button_clicked" swapped="no"/>
-          </object>
-          <packing>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <style>
-          <class name="linked"/>
-        </style>
-      </object>
-    </child>
-    <child>
-      <object class="GtkBox" id="_song_info_box">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="halign">center</property>
-        <property name="has_tooltip">True</property>
-        <property name="valign">center</property>
-        <property name="spacing">8</property>
-        <signal name="query-tooltip" handler="_on_tooltip_query"/>
-        <child>
-          <object class="CoverStack" id="_cover_stack">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-          </object>
-          <packing>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkBox" id="nowplaying_labels">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="halign">center</property>
-            <property name="valign">center</property>
-            <property name="orientation">vertical</property>
-            <property name="homogeneous">True</property>
-            <child>
-              <object class="GtkLabel" id="_title_label">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">start</property>
-                <property name="valign">start</property>
-                <property name="xalign">0</property>
-                <property name="ellipsize">middle</property>
-                <property name="width_chars">8</property>
-                <property name="max_width_chars">42</property>
-                <style>
-                  <class name="player-title-label"/>
-                </style>
-              </object>
-              <packing>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkLabel" id="_artist_label">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">start</property>
-                <property name="valign">start</property>
-                <property name="xalign">0</property>
-                <property name="ellipsize">middle</property>
-                <property name="width_chars">8</property>
-                <property name="max_width_chars">42</property>
-                <style>
-                  <class name="player-artist-label"/>
-                </style>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <child>
-      <object class="SmoothScale" id="_progress_scale">
-        <property name="visible">True</property>
-        <property name="can_focus">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"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkBox" id="timer">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="halign">start</property>
-        <property name="valign">center</property>
-        <property name="spacing">6</property>
-        <child>
-          <object class="GtkLabel" id="_progress_time_label">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="halign">start</property>
-            <property name="valign">center</property>
-            <property name="label">0:00</property>
-          </object>
-          <packing>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkLabel" id="separator">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="halign">start</property>
-            <property name="valign">center</property>
-            <property name="label">/</property>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkLabel" id="_duration_label">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="halign">start</property>
-            <property name="valign">center</property>
-            <property name="label">0:00</property>
-          </object>
-          <packing>
-            <property name="position">2</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <child>
-      <object class="GtkBox" id="menuBox">
-        <property name="height_request">34</property>
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="halign">end</property>
-        <property name="valign">center</property>
-        <child>
-          <object class="GtkMenuButton" id="menuButton">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="use_popover">True</property>
-            <property name="menu_model">repeatMenu</property>
-            <child>
-              <object class="GtkBox" id="replayBox">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkImage" id="_repeat_image">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon_name">media-playlist-consecutive-symbolic</property>
-                    <property name="icon_size">1</property>
-                  </object>
-                  <packing>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkImage" id="downArrow">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon_name">pan-down-symbolic</property>
-                    <property name="icon_size">1</property>
-                  </object>
-                  <packing>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
+  <property name="visible">False</property>
+  <property name="can_focus">False</property>
+  <property name="hexpand">True</property>
+  <child>
+    <object class="GtkBox" id="buttons">
+      <property name="visible">True</property>
+      <property name="can_focus">False</property>
+      <property name="halign">start</property>
+      <property name="valign">center</property>
+      <child>
+        <object class="GtkButton" id="_prev_button">
+          <property name="width_request">42</property>
+          <property name="visible">True</property>
+          <property name="sensitive">False</property>
+          <property name="can_focus">True</property>
+          <property name="receives_default">True</property>
+          <property name="tooltip_text" translatable="yes">Previous</property>
+          <property name="halign">center</property>
+          <property name="valign">center</property>
+          <property name="image">previous_image</property>
+          <property name="always_show_image">True</property>
+          <signal name="clicked" handler="_on_prev_button_clicked" swapped="no"/>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="fill">True</property>
+          <property name="position">0</property>
+        </packing>
+      </child>
+      <child>
+        <object class="GtkButton" id="_play_button">
+          <property name="width_request">60</property>
+          <property name="visible">True</property>
+          <property name="sensitive">False</property>
+          <property name="can_focus">True</property>
+          <property name="receives_default">True</property>
+          <property name="tooltip_text" translatable="yes">Play</property>
+          <property name="halign">center</property>
+          <property name="valign">center</property>
+          <property name="image">_play_image</property>
+          <property name="always_show_image">True</property>
+          <signal name="clicked" handler="_on_play_button_clicked" swapped="no"/>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="fill">True</property>
+          <property name="position">1</property>
+        </packing>
+      </child>
+      <child>
+        <object class="GtkButton" id="_next_button">
+          <property name="width_request">42</property>
+          <property name="visible">True</property>
+          <property name="sensitive">False</property>
+          <property name="can_focus">True</property>
+          <property name="receives_default">True</property>
+          <property name="tooltip_text" translatable="yes">Next</property>
+          <property name="halign">center</property>
+          <property name="valign">center</property>
+          <property name="image">next_image</property>
+          <property name="always_show_image">True</property>
+          <signal name="clicked" handler="_on_next_button_clicked" swapped="no"/>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="fill">True</property>
+          <property name="position">2</property>
+        </packing>
+      </child>
+      <style>
+        <class name="linked"/>
+      </style>
+    </object>
+    <packing>
+      <property name="position">0</property>
+    </packing>
+  </child>
+  <child>
+    <object class="GtkBox" id="_song_info_box">
+      <property name="visible">True</property>
+      <property name="can_focus">False</property>
+      <property name="has_tooltip">True</property>
+      <property name="halign">center</property>
+      <property name="valign">center</property>
+      <property name="spacing">8</property>
+      <signal name="query-tooltip" handler="_on_tooltip_query" swapped="no"/>
+      <child>
+        <object class="CoverStack" id="_cover_stack">
+          <property name="visible">True</property>
+          <property name="can_focus">False</property>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="fill">True</property>
+          <property name="position">0</property>
+        </packing>
+      </child>
+      <child>
+        <object class="GtkBox" id="nowplaying_labels">
+          <property name="visible">True</property>
+          <property name="can_focus">False</property>
+          <property name="halign">center</property>
+          <property name="valign">center</property>
+          <property name="orientation">vertical</property>
+          <property name="homogeneous">True</property>
+          <child>
+            <object class="GtkLabel" id="_title_label">
+              <property name="visible">True</property>
+              <property name="can_focus">False</property>
+              <property name="halign">start</property>
+              <property name="valign">start</property>
+              <property name="ellipsize">middle</property>
+              <property name="width_chars">8</property>
+              <property name="max_width_chars">42</property>
+              <property name="xalign">0</property>
+              <style>
+                <class name="player-title-label"/>
+              </style>
+            </object>
+            <packing>
+              <property name="expand">False</property>
+              <property name="fill">True</property>
+              <property name="position">0</property>
+            </packing>
+          </child>
+          <child>
+            <object class="GtkLabel" id="_artist_label">
+              <property name="visible">True</property>
+              <property name="can_focus">False</property>
+              <property name="halign">start</property>
+              <property name="valign">start</property>
+              <property name="ellipsize">middle</property>
+              <property name="width_chars">8</property>
+              <property name="max_width_chars">42</property>
+              <property name="xalign">0</property>
+              <style>
+                <class name="player-artist-label"/>
+              </style>
+            </object>
+            <packing>
+              <property name="expand">False</property>
+              <property name="fill">True</property>
+              <property name="position">1</property>
+            </packing>
+          </child>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="fill">True</property>
+          <property name="position">1</property>
+        </packing>
+      </child>
+    </object>
+    <packing>
+      <property name="position">1</property>
+    </packing>
+  </child>
+  <child>
+    <object class="GtkBox" id="timer">
+      <property name="visible">True</property>
+      <property name="can_focus">False</property>
+      <property name="halign">start</property>
+      <property name="valign">center</property>
+      <property name="spacing">6</property>
+      <child>
+        <object class="GtkLabel" id="_progress_time_label">
+          <property name="visible">True</property>
+          <property name="can_focus">False</property>
+          <property name="halign">start</property>
+          <property name="valign">center</property>
+          <property name="label">0:00</property>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="fill">True</property>
+          <property name="position">0</property>
+        </packing>
+      </child>
+      <child>
+        <object class="GtkLabel" id="separator">
+          <property name="visible">True</property>
+          <property name="can_focus">False</property>
+          <property name="halign">start</property>
+          <property name="valign">center</property>
+          <property name="label">/</property>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="fill">True</property>
+          <property name="position">1</property>
+        </packing>
+      </child>
+      <child>
+        <object class="GtkLabel" id="_duration_label">
+          <property name="visible">True</property>
+          <property name="can_focus">False</property>
+          <property name="halign">start</property>
+          <property name="valign">center</property>
+          <property name="label">0:00</property>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="fill">True</property>
+          <property name="position">2</property>
+        </packing>
+      </child>
+    </object>
+    <packing>
+      <property name="position">0</property>
+    </packing>
+  </child>
+  <child>
+    <object class="SmoothScale" id="_progress_scale">
+          <property name="visible">True</property>
+          <property name="can_focus">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"/>
+        </object>
+    <packing>
+      <property name="position">3</property>
+    </packing>
+  </child>
+  <child>
+    <object class="GtkBox" id="_repeat_box">
+      <property name="height_request">34</property>
+      <property name="visible">True</property>
+      <property name="can_focus">False</property>
+      <property name="halign">end</property>
+      <property name="valign">center</property>
+      <child>
+        <object class="GtkMenuButton" id="menuButton">
+          <property name="visible">True</property>
+          <property name="can_focus">True</property>
+          <property name="receives_default">True</property>
+          <child>
+            <object class="GtkBox" id="replayBox">
+              <property name="visible">True</property>
+              <property name="can_focus">False</property>
+              <property name="spacing">6</property>
+              <child>
+                <object class="GtkImage" id="_repeat_image">
+                  <property name="visible">True</property>
+                  <property name="can_focus">False</property>
+                  <property name="icon_name">media-playlist-consecutive-symbolic</property>
+                  <property name="icon_size">1</property>
+                </object>
+                <packing>
+                  <property name="expand">False</property>
+                  <property name="fill">True</property>
+                  <property name="position">0</property>
+                </packing>
+              </child>
+              <child>
+                <object class="GtkImage" id="downArrow">
+                  <property name="visible">True</property>
+                  <property name="can_focus">False</property>
+                  <property name="icon_name">pan-down-symbolic</property>
+                  <property name="icon_size">1</property>
+                </object>
+                <packing>
+                  <property name="expand">False</property>
+                  <property name="fill">True</property>
+                  <property name="position">1</property>
+                </packing>
+              </child>
+            </object>
+          </child>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="fill">True</property>
+          <property name="pack_type">end</property>
+          <property name="position">0</property>
+        </packing>
+      </child>
+    </object>
+    <packing>
+      <property name="position">5</property>
+    </packing>
+  </child>
   </template>
   <object class="GtkRadioMenuItem" id="radiomenuitem1">
     <property name="visible">True</property>
diff --git a/data/ui/Window.ui b/data/ui/Window.ui
index 558960a5..72fcabb4 100644
--- a/data/ui/Window.ui
+++ b/data/ui/Window.ui
@@ -1,23 +1,36 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
 <interface>
+  <requires lib="gtk+" version="3.10"/>
+  <requires lib="libhandy" version="0.0"/>
   <template class="Window" parent="GtkApplicationWindow">
-    <property name="default-height">500</property>
-    <property name="default-width">300</property>
+    <property name="can_focus">False</property>
+    <property name="default_width">300</property>
+    <property name="default_height">500</property>
+    <child>
+      <placeholder/>
+    </child>
     <child>
       <object class="GtkBox" id="_box">
-        <property name="orientation">vertical</property>
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
         <child>
           <object class="GtkOverlay" id="_overlay">
-            <property name="vexpand">True</property>
             <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="vexpand">True</property>
             <child type="overlay">
               <object class="GtkStack" id="_stack">
-                <property name="can-focus">False</property>
-                <property name="homogeneous">False</property>
-                <property name="transition-duration">100</property>
-                <property name="transition-type">crossfade</property>
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hhomogeneous">False</property>
+                <property name="vhomogeneous">False</property>
+                <property name="transition_duration">100</property>
+                <property name="transition_type">crossfade</property>
+                <child>
+                  <placeholder/>
+                </child>
               </object>
             </child>
             <child type="overlay">
@@ -26,11 +39,36 @@
                 <property name="transition-type">slide-down</property>
                 <property name="valign">start</property>
               </object>
+              <packing>
+                <property name="index">1</property>
+              </packing>
             </child>
           </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="HdyViewSwitcherBar" id="_switcher_bar">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="reveal">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
         </child>
         <child>
           <object class="SelectionToolbar" id="_selection_toolbar"/>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
         </child>
       </object>
     </child>
diff --git a/gnome-music.in b/gnome-music.in
index fe0de970..fda229fa 100755
--- a/gnome-music.in
+++ b/gnome-music.in
@@ -47,9 +47,12 @@ import gi
 gi.require_version('Gtk', '3.0')
 gi.require_version('GIRepository', '2.0')
 gi.require_version('Gst', '1.0')
-from gi.repository import GIRepository, Gio, Gtk, Gst
+gi.require_version('Handy', '0.0')
+from gi.repository import GIRepository, Gio, Gtk, Gst, Handy
 
 Gst.init(None)
+Handy.init(None)
+
 
 LOCALE_DIR = '@localedir@'
 PKGDATA_DIR = '@pkgdatadir@'
diff --git a/gnomemusic/utils.py b/gnomemusic/utils.py
index 76310cb6..7cceaf15 100644
--- a/gnomemusic/utils.py
+++ b/gnomemusic/utils.py
@@ -44,6 +44,12 @@ class View(IntEnum):
     SEARCH = 5
 
 
+class AdaptiveViewMode(IntEnum):
+    MOBILE = 0
+    TABLET = 1
+    DESKTOP = 2
+
+
 def get_album_title(item):
     """Returns the album title associated with the media item
 
diff --git a/gnomemusic/views/albumsview.py b/gnomemusic/views/albumsview.py
index c0f70a91..d69a7334 100644
--- a/gnomemusic/views/albumsview.py
+++ b/gnomemusic/views/albumsview.py
@@ -25,6 +25,7 @@
 from gettext import gettext as _
 from gi.repository import GObject, Gtk
 
+from gnomemusic.utils import AdaptiveViewMode
 from gnomemusic.widgets.headerbar import HeaderBar
 from gnomemusic.widgets.albumcover import AlbumCover
 from gnomemusic.widgets.albumwidget import AlbumWidget
@@ -39,6 +40,7 @@ class AlbumsView(Gtk.Stack):
 
     __gtype_name__ = "AlbumsView"
 
+    adaptive_view = GObject.Property(type=int, default=AdaptiveViewMode.MOBILE)
     search_mode_active = GObject.Property(type=bool, default=False)
     selected_items_count = GObject.Property(type=int, default=0, minimum=0)
     selection_mode = GObject.Property(type=bool, default=False)
@@ -59,6 +61,7 @@ class AlbumsView(Gtk.Stack):
         # FIXME: Make these properties.
         self.name = "albums"
         self.title = _("Albums")
+        self.icon = "media-optical-cd-audio-symbolic"
 
         self._window = application.props.window
         self._headerbar = self._window._headerbar
@@ -77,14 +80,25 @@ class AlbumsView(Gtk.Stack):
         self._album_widget.bind_property(
             "selection-mode", self, "selection-mode",
             GObject.BindingFlags.BIDIRECTIONAL)
+        self._album_widget.bind_property(
+            "adaptive-view", self, "adaptive-view",
+            GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE)
 
         self.add(self._album_widget)
 
+        self.connect("notify::adaptive-view", self._on_adaptive_view_changed)
         self.connect(
             "notify::search-mode-active", self._on_search_mode_changed)
-
         self.show_all()
 
+    def _on_adaptive_view_changed(self, widget, param):
+        if self.props.adaptive_view == AdaptiveViewMode.MOBILE:
+            self._flowbox.set_max_children_per_line(2)
+        elif self.props.adaptive_view == AdaptiveViewMode.TABLET:
+            self._flowbox.set_max_children_per_line(4)
+        else:
+            self._flowbox.set_max_children_per_line(8)
+
     def _on_selection_mode_changed(self, widget, data=None):
         if not self.props.selection_mode:
             self.unselect_all()
@@ -129,8 +143,8 @@ class AlbumsView(Gtk.Stack):
 
     def _set_album_headerbar(self, corealbum):
         self._headerbar.props.state = HeaderBar.State.CHILD
-        self._headerbar.props.title = corealbum.props.title
-        self._headerbar.props.subtitle = corealbum.props.artist
+        self._headerbar.set_title(corealbum.props.title)
+        self._headerbar.set_subtitle(corealbum.props.artist)
 
     def _toggle_all_selection(self, selected):
         """
diff --git a/gnomemusic/views/artistsview.py b/gnomemusic/views/artistsview.py
index 76f928b6..86a37c26 100644
--- a/gnomemusic/views/artistsview.py
+++ b/gnomemusic/views/artistsview.py
@@ -24,10 +24,11 @@
 
 import logging
 from gettext import gettext as _
-from gi.repository import Gdk, Gtk
+from gi.repository import Gdk, Gtk, GObject
 
 from gnomemusic import log
 from gnomemusic.views.baseview import BaseView
+from gnomemusic.utils import AdaptiveViewMode
 from gnomemusic.widgets.artistalbumswidget import ArtistAlbumsWidget
 from gnomemusic.widgets.artisttile import ArtistTile
 
@@ -53,10 +54,11 @@ class ArtistsView(BaseView):
         """
         self._sidebar = Gtk.ListBox()
         sidebar_container = Gtk.ScrolledWindow()
+        sidebar_container.props.width_request = 285
         sidebar_container.add(self._sidebar)
 
         super().__init__(
-            'artists', _("Artists"), application, sidebar_container)
+            'artists', _("Artists"), "system-users-symbolic", application, sidebar_container)
 
         self._application = application
         self._artists = {}
@@ -71,7 +73,6 @@ class ArtistsView(BaseView):
         self._loaded_id = self._coremodel.connect(
             "artists-loaded", self._on_artists_loaded)
 
-        sidebar_container.props.width_request = 220
         sidebar_container.get_style_context().add_class('sidebar')
         self._sidebar.props.selection_mode = Gtk.SelectionMode.SINGLE
         self._sidebar.connect('row-activated', self._on_artist_activated)
@@ -127,6 +128,7 @@ class ArtistsView(BaseView):
 
         self._sidebar.select_row(first_row)
         first_row.emit("activate")
+        self.view_sidebar()
 
     @log
     def _setup_view(self):
@@ -135,13 +137,16 @@ class ArtistsView(BaseView):
 
         self._view = Gtk.Stack(
             transition_type=Gtk.StackTransitionType.CROSSFADE,
-            vhomogeneous=False)
+            homogeneous=False)
         self._view_container.add(self._view)
 
     @log
     def _on_artist_activated(self, sidebar, row, data=None):
         """Initializes new artist album widgets"""
         artist_tile = row.get_child()
+        if self.props.adaptive_view == AdaptiveViewMode.MOBILE:
+            self.view_content()
+
         if self.props.selection_mode:
             artist_tile.props.selected = not artist_tile.props.selected
             return
@@ -156,6 +161,12 @@ class ArtistsView(BaseView):
 
         self._artist_albums = ArtistAlbumsWidget(
             coreartist, self._application, False)
+
+        self.bind_property(
+            'adaptive-view', self._artist_albums, 'adaptive-view',
+            GObject.BindingFlags.DEFAULT
+            | GObject.BindingFlags.SYNC_CREATE)
+
         artist_albums_frame = Gtk.Frame(
             shadow_type=Gtk.ShadowType.NONE, hexpand=True)
         artist_albums_frame.add(self._artist_albums)
diff --git a/gnomemusic/views/baseview.py b/gnomemusic/views/baseview.py
index 08b9d26f..6a179821 100644
--- a/gnomemusic/views/baseview.py
+++ b/gnomemusic/views/baseview.py
@@ -22,8 +22,11 @@
 # code, but you are not obligated to do so.  If you do not wish to do so,
 # delete this exception statement from your version.
 
-from gi.repository import GObject, Gtk
+from gi.repository import GObject, Gtk, Handy
 
+from enum import IntEnum
+from gnomemusic.widgets.headerbar import HeaderBar
+from gnomemusic.utils import AdaptiveViewMode
 from gnomemusic import log
 
 
@@ -32,37 +35,43 @@ class BaseView(Gtk.Stack):
 
     selected_items_count = GObject.Property(type=int, default=0, minimum=0)
     selection_mode = GObject.Property(type=bool, default=False)
+    adaptive_view = GObject.Property(type=int, default=AdaptiveViewMode.MOBILE)
 
     def __repr__(self):
         return '<BaseView>'
 
     @log
-    def __init__(self, name, title, application, sidebar=None):
+    def __init__(self, name, title, icon, application, sidebar=None):
         """Initialize
         :param name: The view name
         :param title: The view title
         :param GtkApplication application: The application object
         :param sidebar: The sidebar object (Default: Gtk.Box)
         """
-        super().__init__(transition_type=Gtk.StackTransitionType.CROSSFADE)
+        Gtk.Stack.__init__(self, transition_type=Gtk.StackTransitionType.CROSSFADE, homogeneous=False)
+        self._leaflet = Handy.Leaflet()
+        self._leaflet.props.vexpand = True
 
         self._grid = Gtk.Grid(orientation=Gtk.Orientation.HORIZONTAL)
         self._box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
 
         # Setup the main view
         self._setup_view()
+        self._sidebar_widget = sidebar
 
         if sidebar:
-            self._grid.add(sidebar)
+            self._leaflet.add(sidebar)
 
-        self._grid.add(self._box)
+        self._leaflet.add(self._box)
 
         self._window = application.props.window
         self._headerbar = self._window._headerbar
 
         self.name = name
         self.title = title
+        self.icon = icon
 
+        self._grid.add(self._leaflet)
         self.add(self._grid)
         self.show_all()
 
@@ -73,6 +82,21 @@ class BaseView(Gtk.Stack):
             'selection-mode', self._window, 'selection-mode',
             GObject.BindingFlags.BIDIRECTIONAL)
 
+    def is_folded(self):
+        return self._leaflet.get_folded()
+
+    def view_content(self):
+        self._leaflet.set_visible_child(self._box)
+        self._headerbar.props.state = HeaderBar.State.CHILD
+
+    def view_sidebar(self):
+        if self._sidebar_widget:
+            self._leaflet.set_visible_child(self._sidebar_widget)
+            self._headerbar.props.state = HeaderBar.State.MAIN
+
+    def _back_button_clicked(self, view):
+        self.view_sidebar()
+
     @log
     def _setup_view(self):
         """Instantiate and set up the view object"""
diff --git a/gnomemusic/views/playlistsview.py b/gnomemusic/views/playlistsview.py
index b7ab67c9..ee9ffe3e 100644
--- a/gnomemusic/views/playlistsview.py
+++ b/gnomemusic/views/playlistsview.py
@@ -24,7 +24,7 @@
 
 from gettext import gettext as _
 
-from gi.repository import Gdk, GObject, Gio, Gtk
+from gi.repository import Gdk, GObject, Gio, Gtk, Handy
 
 from gnomemusic import log
 from gnomemusic.player import PlayerPlaylist
@@ -35,7 +35,7 @@ from gnomemusic.widgets.playlistcontrols import PlaylistControls
 from gnomemusic.widgets.playlistdialog import PlaylistDialog
 from gnomemusic.widgets.playlisttile import PlaylistTile
 from gnomemusic.widgets.songwidget import SongWidget
-
+from gnomemusic.utils import AdaptiveViewMode
 
 class PlaylistsView(BaseView):
     """Main view for playlists"""
@@ -52,18 +52,19 @@ class PlaylistsView(BaseView):
         """
         self._sidebar = Gtk.ListBox()
         sidebar_container = Gtk.ScrolledWindow()
+        sidebar_container.props.width_request = 285
         sidebar_container.add(self._sidebar)
 
+        self._pl_ctrls = PlaylistControls()
+
         super().__init__(
-            'playlists', _("Playlists"), application, sidebar_container)
+            'playlists', _("Playlists"), "view-list-symbolic", application, sidebar_container)
 
         self._coremodel = application.props.coremodel
         self._model = self._coremodel.props.playlists_sort
         self._window = application.props.window
         self._player = player
 
-        self._pl_ctrls = PlaylistControls()
-
         self._song_popover = PlaylistContextMenu(self._view)
 
         play_song = Gio.SimpleAction.new('play_song', None)
@@ -97,17 +98,10 @@ class PlaylistsView(BaseView):
             'activate', self._stage_playlist_for_renaming)
         self._window.add_action(self._playlist_rename_action)
 
-        self._grid.insert_row(0)
-        self._grid.attach(self._pl_ctrls, 1, 0, 1, 1)
-
-        sidebar_container.set_size_request(220, -1)
         sidebar_container.get_style_context().add_class('sidebar')
         self._sidebar.set_selection_mode(Gtk.SelectionMode.SINGLE)
         self._sidebar.connect('row-activated', self._on_playlist_activated)
 
-        self._grid.child_set_property(sidebar_container, 'top-attach', 0)
-        self._grid.child_set_property(sidebar_container, 'height', 2)
-
         self._sidebar.bind_model(self._model, self._add_playlist_to_sidebar)
 
         self._loaded_id = self._coremodel.connect(
@@ -118,18 +112,26 @@ class PlaylistsView(BaseView):
         # Selection is only possible from the context menu
         self.disconnect(self._selection_mode_id)
 
+        self.connect(
+            "notify::adaptive-view", self._on_adaptive_view_changed)
         self.show_all()
 
     @log
     def _setup_view(self):
-        view_container = Gtk.ScrolledWindow(hexpand=True, vexpand=True)
-        self._box.pack_start(view_container, True, True, 0)
+        main_container = Gtk.ScrolledWindow()
+        main_container.show()
+
+        self._view_container = Handy.Column()
+        self._view_container.set_maximum_width(800)
+        self._view_container.set_linear_growth_width(800)
+
+        container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+        container.show()
+
+        container.add(self._pl_ctrls)
 
         self._view = Gtk.ListBox()
         self._view.get_style_context().add_class("songs-list")
-        self._view.props.margin_top = 20
-        self._view.props.margin_left = 80
-        self._view.props.margin_right = 80
         self._view.props.valign = Gtk.Align.START
 
         self._controller = Gtk.GestureMultiPress().new(self._view)
@@ -137,7 +139,10 @@ class PlaylistsView(BaseView):
         self._controller.props.button = Gdk.BUTTON_SECONDARY
         self._controller.connect("pressed", self._on_view_right_clicked)
 
-        view_container.add(self._view)
+        container.add(self._view)
+        self._view_container.add(container)
+        main_container.add(self._view_container)
+        self._box.pack_start(main_container, True, True, 0)
 
     @log
     def _add_playlist_to_sidebar(self, playlist):
@@ -149,11 +154,22 @@ class PlaylistsView(BaseView):
         row = PlaylistTile(playlist)
         return row
 
+    def _on_adaptive_view_changed(self, widget, param):
+        if self.props.adaptive_view == AdaptiveViewMode.MOBILE:
+            self._view_container.set_margin_top(32)
+            self._view_container.set_margin_right(0)
+            self._view_container.set_margin_left(0)
+        else:
+            self._view_container.set_margin_top(32)
+            self._view_container.set_margin_right(32)
+            self._view_container.set_margin_left(32)
+
     def _on_playlists_loaded(self, klass):
         self._coremodel.disconnect(self._loaded_id)
         first_row = self._sidebar.get_row_at_index(0)
         self._sidebar.select_row(first_row)
         first_row.emit("activate")
+        self.view_sidebar()
 
     @log
     def _on_view_right_clicked(self, gesture, n_press, x, y):
@@ -209,6 +225,8 @@ class PlaylistsView(BaseView):
     def _on_playlist_activated(self, sidebar, row, data=None):
         """Update view with content from selected playlist"""
         playlist = row.props.playlist
+        if self.props.adaptive_view == AdaptiveViewMode.MOBILE:
+            self.view_content()
 
         if self.rename_active:
             self._pl_ctrls.disable_rename_playlist()
diff --git a/gnomemusic/views/songsview.py b/gnomemusic/views/songsview.py
index c56c4dc2..3f5e7359 100644
--- a/gnomemusic/views/songsview.py
+++ b/gnomemusic/views/songsview.py
@@ -54,7 +54,7 @@ class SongsView(BaseView):
         :param player: The main player object
         """
         self._coremodel = application.props.coremodel
-        super().__init__('songs', _("Songs"), application)
+        super().__init__('songs', _("Songs"), "emblem-music-symbolic", application)
 
         self._iter_to_clean = None
 
diff --git a/gnomemusic/widgets/albumwidget.py b/gnomemusic/widgets/albumwidget.py
index 63856756..bb314de6 100644
--- a/gnomemusic/widgets/albumwidget.py
+++ b/gnomemusic/widgets/albumwidget.py
@@ -4,6 +4,7 @@ from gi.repository import GObject, Grl, Gtk
 from gnomemusic import log
 from gnomemusic.albumartcache import Art
 from gnomemusic.player import PlayerPlaylist
+from gnomemusic.utils import AdaptiveViewMode
 from gnomemusic.widgets.disclistboxwidget import DiscBox
 from gnomemusic.widgets.disclistboxwidget import DiscListBox  # noqa: F401
 
@@ -27,6 +28,10 @@ class AlbumWidget(Gtk.EventBox):
     _running_info_label = Gtk.Template.Child()
     _title_label = Gtk.Template.Child()
 
+    _album_widget = Gtk.Template.Child()
+    _album_info = Gtk.Template.Child()
+
+    adaptive_view = GObject.Property(type=int, default=AdaptiveViewMode.MOBILE)
     selected_items_count = GObject.Property(type=int, default=0, minimum=0)
     selection_mode = GObject.Property(type=bool, default=False)
 
@@ -49,6 +54,7 @@ class AlbumWidget(Gtk.EventBox):
         self._duration_signal_id = None
         self._model_signal_id = None
 
+        self.connect("notify::adaptive-view", self._on_adaptive_view_changed)
         self._cover_stack.props.size = Art.Size.LARGE
         self._parent_view = parent_view
         self._player = player
@@ -92,6 +98,18 @@ class AlbumWidget(Gtk.EventBox):
 
         self._album_model.items_changed(0, 0, 0)
 
+    def _on_adaptive_view_changed(self, widget, param):
+        if self.props.adaptive_view == AdaptiveViewMode.MOBILE:
+            self._album_widget.set_orientation(Gtk.Orientation.VERTICAL)
+            self._album_widget.set_margin_top(32)
+            self._album_widget.set_margin_right(0)
+            self._album_widget.set_margin_left(0)
+        else:
+            self._album_widget.set_orientation(Gtk.Orientation.HORIZONTAL)
+            self._album_widget.set_margin_top(32)
+            self._album_widget.set_margin_right(32)
+            self._album_widget.set_margin_left(32)
+
     def _create_widget(self, disc):
         disc_box = self._create_disc_box(
             disc.props.disc_nr, disc.model)
diff --git a/gnomemusic/widgets/artistalbumswidget.py b/gnomemusic/widgets/artistalbumswidget.py
index 114ff46b..4a8a6918 100644
--- a/gnomemusic/widgets/artistalbumswidget.py
+++ b/gnomemusic/widgets/artistalbumswidget.py
@@ -28,6 +28,7 @@ from gi.repository import GObject, Gtk
 
 from gnomemusic import log
 from gnomemusic.player import PlayerPlaylist
+from gnomemusic.utils import AdaptiveViewMode
 from gnomemusic.widgets.artistalbumwidget import ArtistAlbumWidget
 
 logger = logging.getLogger(__name__)
@@ -43,6 +44,7 @@ class ArtistAlbumsWidget(Gtk.ListBox):
 
     __gtype_name__ = 'ArtistAlbumsWidget'
 
+    adaptive_view = GObject.Property(type=int, default=AdaptiveViewMode.MOBILE)
     selected_items_count = GObject.Property(type=int, default=0, minimum=0)
     selection_mode = GObject.Property(type=bool, default=False)
 
@@ -100,6 +102,11 @@ class ArtistAlbumsWidget(Gtk.ListBox):
             GObject.BindingFlags.BIDIRECTIONAL
             | GObject.BindingFlags.SYNC_CREATE)
 
+        self.bind_property(
+            'adaptive-view', widget, 'adaptive-view',
+            GObject.BindingFlags.BIDIRECTIONAL
+            | GObject.BindingFlags.SYNC_CREATE)
+
         row.add(widget)
         self._widgets.append(widget)
         widget.connect("song-activated", self._song_activated)
diff --git a/gnomemusic/widgets/artistalbumwidget.py b/gnomemusic/widgets/artistalbumwidget.py
index 9d90fb2c..e89510fa 100644
--- a/gnomemusic/widgets/artistalbumwidget.py
+++ b/gnomemusic/widgets/artistalbumwidget.py
@@ -22,16 +22,17 @@
 # code, but you are not obligated to do so.  If you do not wish to do so,
 # delete this exception statement from your version.
 
-from gi.repository import GObject, Gtk
+from gi.repository import GObject, Gtk, Handy
 
 from gnomemusic import log
 from gnomemusic.albumartcache import Art
 from gnomemusic.widgets.disclistboxwidget import DiscBox
+from gnomemusic.utils import AdaptiveViewMode
 from gnomemusic.widgets.songwidget import SongWidget
 
 
 @Gtk.Template(resource_path='/org/gnome/Music/ui/ArtistAlbumWidget.ui')
-class ArtistAlbumWidget(Gtk.Box):
+class ArtistAlbumWidget(Handy.Column):
 
     __gtype_name__ = 'ArtistAlbumWidget'
 
@@ -40,6 +41,7 @@ class ArtistAlbumWidget(Gtk.Box):
     _disc_list_box = Gtk.Template.Child()
     _title_year = Gtk.Template.Child()
 
+    adaptive_view = GObject.Property(type=int, default=AdaptiveViewMode.MOBILE)
     selection_mode = GObject.Property(type=bool, default=False)
 
     __gsignals__ = {
@@ -54,7 +56,7 @@ class ArtistAlbumWidget(Gtk.Box):
     def __init__(
             self, corealbum, selection_mode_allowed, size_group=None,
             cover_size_group=None):
-        super().__init__(orientation=Gtk.Orientation.HORIZONTAL)
+        super().__init__()
 
         self._size_group = size_group
         self._cover_size_group = cover_size_group
@@ -90,6 +92,18 @@ class ArtistAlbumWidget(Gtk.Box):
             corealbum.props.model, self._create_widget)
 
         corealbum.props.model.items_changed(0, 0, 0)
+        self.connect("notify::adaptive-view", self._on_adaptive_view_changed)
+
+    def _on_adaptive_view_changed(self, widget, param):
+
+        if self.props.adaptive_view == AdaptiveViewMode.MOBILE:
+            self._cover_stack.set_halign(Gtk.Align.CENTER)
+            self.set_margin_right(0)
+            self.set_margin_left(0)
+        else:
+            self._cover_stack.set_halign(Gtk.Align.START)
+            self.set_margin_right(32)
+            self.set_margin_left(32)
 
     def _create_widget(self, disc):
         disc_box = self._create_disc_box(disc.props.disc_nr, disc.model)
diff --git a/gnomemusic/widgets/headerbar.py b/gnomemusic/widgets/headerbar.py
index e01d81e1..50a40888 100644
--- a/gnomemusic/widgets/headerbar.py
+++ b/gnomemusic/widgets/headerbar.py
@@ -86,6 +86,16 @@ class HeaderBar(Gtk.HeaderBar):
         SEARCH = 2
         EMPTY = 3
 
+    class View(IntEnum):
+        """The three different views of the HeaderBar
+
+            They are switched between using HdySqueezer and
+            on the current visible window width
+        """
+        TITLE = 0
+        NARROW = 1
+        WIDE = 2
+
     __gtype_name__ = "HeaderBar"
 
     __gsignals__ = {
@@ -98,6 +108,14 @@ class HeaderBar(Gtk.HeaderBar):
     _back_button = Gtk.Template.Child()
     _menu_button = Gtk.Template.Child()
 
+    _squeezer = Gtk.Template.Child()
+    _title_text = Gtk.Template.Child()
+    _title_wide_switcher  = Gtk.Template.Child()
+    _title_narrow_switcher = Gtk.Template.Child()
+
+    _title_label = Gtk.Template.Child()
+    _subtitle_label = Gtk.Template.Child()
+
     search_mode_active = GObject.Property(type=bool, default=False)
     selected_items_count = GObject.Property(type=int, default=0, minimum=0)
     selection_mode_allowed = GObject.Property(type=bool, default=True)
@@ -112,10 +130,6 @@ class HeaderBar(Gtk.HeaderBar):
 
         self._selection_mode = False
 
-        self._stack_switcher = Gtk.StackSwitcher(
-            can_focus=False, halign="center")
-        self._stack_switcher.show()
-
         self._selection_menu = SelectionBarMenuButton()
 
         self._menu_button.set_popover(AppMenu())
@@ -133,7 +147,11 @@ class HeaderBar(Gtk.HeaderBar):
             "selection-mode", self._select_button, "active",
             GObject.BindingFlags.BIDIRECTIONAL)
         self.bind_property(
-            "stack", self._stack_switcher, "stack",
+            "stack", self._title_wide_switcher, "stack",
+            GObject.BindingFlags.BIDIRECTIONAL
+            | GObject.BindingFlags.SYNC_CREATE)
+        self.bind_property(
+            "stack", self._title_narrow_switcher, "stack",
             GObject.BindingFlags.BIDIRECTIONAL
             | GObject.BindingFlags.SYNC_CREATE)
         self.bind_property(
@@ -148,6 +166,12 @@ class HeaderBar(Gtk.HeaderBar):
             "notify::selection-mode-allowed",
             self._on_selection_mode_allowed_changed)
 
+    def set_title(self, title):
+        self._title_label.set_text(title)
+
+    def set_subtitle(self, subtitle):
+        self._subtitle_label.set_text(subtitle)
+
     @GObject.Property(type=bool, default=False)
     def selection_mode(self):
         """Selection mode
@@ -173,6 +197,28 @@ class HeaderBar(Gtk.HeaderBar):
 
         self._update()
 
+    @GObject.Property
+    def view(self):
+        return self._view
+
+    @view.setter
+    def view(self, value):
+        """Set view of the of widget
+
+        This influences the look and functionality of the headerbar.
+
+        :param HeaderBar.View value: Widget view
+        """
+        self._view = value
+        if value == HeaderBar.View.WIDE:
+            self._squeezer.set_child_enabled(self._title_wide_switcher,
+                                            True)
+        elif value == HeaderBar.View.NARROW:
+            self._squeezer.set_child_enabled(self._title_narrow_switcher,
+                                              True)
+        else:
+            self._squeezer.set_child_enabled(self._title_text, True)
+
     @GObject.Property
     def state(self):
         """State of the widget
@@ -199,11 +245,11 @@ class HeaderBar(Gtk.HeaderBar):
         if value == HeaderBar.State.EMPTY:
             self._search_button.props.sensitive = False
             self._select_button.props.sensitive = False
-            self._stack_switcher.hide()
+            self._squeezer.hide()
         else:
             self._search_button.props.sensitive = True
             self._select_button.props.sensitive = True
-            self._stack_switcher.show()
+            self._squeezer.show()
 
     @Gtk.Template.Callback()
     @log
@@ -219,10 +265,10 @@ class HeaderBar(Gtk.HeaderBar):
     def _update(self):
         if self.props.selection_mode:
             self.props.custom_title = self._selection_menu
-        elif self.props.state != HeaderBar.State.MAIN:
+        elif self.props.state == HeaderBar.State.EMPTY:
             self.props.custom_title = None
         else:
-            self.props.custom_title = self._stack_switcher
+            self.props.custom_title = self._squeezer
 
         self._back_button.props.visible = (
             not self.props.selection_mode
diff --git a/gnomemusic/widgets/playertoolbar.py b/gnomemusic/widgets/playertoolbar.py
index d094597f..5f3a9380 100644
--- a/gnomemusic/widgets/playertoolbar.py
+++ b/gnomemusic/widgets/playertoolbar.py
@@ -32,6 +32,7 @@ from gnomemusic.player import Player, RepeatMode
 from gnomemusic.widgets.coverstack import CoverStack  # noqa: F401
 from gnomemusic.widgets.smoothscale import SmoothScale  # noqa: F401
 from gnomemusic.widgets.twolinetip import TwoLineTip
+from gnomemusic.utils import AdaptiveViewMode
 import gnomemusic.utils as utils
 
 
@@ -41,9 +42,10 @@ class PlayerToolbar(Gtk.ActionBar):
 
     Contains the ui of playing a song with Music.
     """
-
     __gtype_name__ = 'PlayerToolbar'
 
+    adaptive_view = GObject.Property(type=int, default=AdaptiveViewMode.MOBILE)
+
     _artist_label = Gtk.Template.Child()
     _cover_stack = Gtk.Template.Child()
     _duration_label = Gtk.Template.Child()
@@ -57,6 +59,10 @@ class PlayerToolbar(Gtk.ActionBar):
     _repeat_image = Gtk.Template.Child()
     _song_info_box = Gtk.Template.Child()
     _title_label = Gtk.Template.Child()
+    _repeat_box = Gtk.Template.Child()
+    nowplaying_labels = Gtk.Template.Child()
+    timer = Gtk.Template.Child()
+    buttons = Gtk.Template.Child()
 
     _repeat_dict = {
         RepeatMode.ALL: "media-playlist-repeat-symbolic",
@@ -75,6 +81,7 @@ class PlayerToolbar(Gtk.ActionBar):
         self._player = None
 
         self._cover_stack.props.size = Art.Size.XSMALL
+        self.connect("notify::adaptive-view", self._on_adaptive_view_changed)
 
         self._tooltip = TwoLineTip()
 
@@ -110,6 +117,25 @@ class PlayerToolbar(Gtk.ActionBar):
 
         self._sync_repeat_image()
 
+    def _on_adaptive_view_changed(self, widget, param):
+
+        if self.props.adaptive_view != AdaptiveViewMode.DESKTOP:
+            self._progress_scale.hide()
+            self._repeat_box.hide()
+            self._prev_button.hide()
+            self._next_button.hide()
+            self.timer.hide()
+            self._cover_stack.props.size = Art.Size.XSMALL
+            self.child_set_property(self.buttons, "pack-type", Gtk.PackType.END)
+        else:
+            self._progress_scale.show()
+            self._repeat_box.show()
+            self._prev_button.show()
+            self._next_button.show()
+            self.timer.show()
+            self._cover_stack.props.size = Art.Size.SMALL
+            self.child_set_property(self.buttons, "pack-type", Gtk.PackType.START)
+
     @Gtk.Template.Callback()
     @log
     def _on_progress_value_changed(self, progress_scale):
@@ -125,6 +151,10 @@ class PlayerToolbar(Gtk.ActionBar):
     @log
     def _on_play_button_clicked(self, button):
         self._player.play_pause()
+        if self._player.props.state != Playback.PLAYING:
+            self.hide()
+        else:
+            self.show()
 
     @Gtk.Template.Callback()
     @log
diff --git a/gnomemusic/widgets/searchheaderbar.py b/gnomemusic/widgets/searchheaderbar.py
index 0e56443a..27f5abf0 100644
--- a/gnomemusic/widgets/searchheaderbar.py
+++ b/gnomemusic/widgets/searchheaderbar.py
@@ -70,7 +70,7 @@ class SearchHeaderBar(Gtk.HeaderBar):
         self._entry = Gd.TaggedEntry()
         self._entry.props.halign = Gtk.Align.CENTER
         self._entry.props.visible = True
-        self._entry.props.width_request = 500
+        # self._entry.props.width_request = 500
 
         self._selection_menu = SelectionBarMenuButton()
 
diff --git a/gnomemusic/window.py b/gnomemusic/window.py
index d805e992..1580ce58 100644
--- a/gnomemusic/window.py
+++ b/gnomemusic/window.py
@@ -31,7 +31,7 @@ from gnomemusic.mediakeys import MediaKeys
 from gnomemusic.player import RepeatMode
 from gnomemusic.search import Search
 from gnomemusic.trackerwrapper import TrackerState
-from gnomemusic.utils import View
+from gnomemusic.utils import View, AdaptiveViewMode
 from gnomemusic.views.albumsview import AlbumsView
 from gnomemusic.views.artistsview import ArtistsView
 from gnomemusic.views.emptyview import EmptyView
@@ -55,6 +55,7 @@ class Window(Gtk.ApplicationWindow):
 
     __gtype_name__ = "Window"
 
+    adaptive_view = GObject.Property(type=GObject.TYPE_INT, default=AdaptiveViewMode.MOBILE)
     selected_items_count = GObject.Property(type=int, default=0, minimum=0)
     selection_mode = GObject.Property(type=bool, default=False)
 
@@ -64,6 +65,8 @@ class Window(Gtk.ApplicationWindow):
     _selection_toolbar = Gtk.Template.Child()
     _stack = Gtk.Template.Child()
 
+    _switcher_bar = Gtk.Template.Child()
+
     def __repr__(self):
         return '<Window>'
 
@@ -132,6 +135,8 @@ class Window(Gtk.ApplicationWindow):
             "notify::search-mode-active", self._on_search_mode_changed)
 
         self._player_toolbar = PlayerToolbar()
+        self._player_toolbar.bind_property("adaptive-view", self, "adaptive-view",
+                                            GObject.BindingFlags.BIDIRECTIONAL | 
GObject.BindingFlags.SYNC_CREATE)
         self._player_toolbar.props.player = self._player
 
         self._headerbar.connect(
@@ -153,6 +158,7 @@ class Window(Gtk.ApplicationWindow):
             "selection-mode", self._search_headerbar, "selection-mode",
             GObject.BindingFlags.BIDIRECTIONAL
             | GObject.BindingFlags.SYNC_CREATE)
+
         self.bind_property(
             "selection-mode", self._player_toolbar, "visible",
             GObject.BindingFlags.INVERT_BOOLEAN)
@@ -172,7 +178,8 @@ class Window(Gtk.ApplicationWindow):
         # bottom line of the searchbar
         self._stack.get_style_context().add_class('background')
 
-        self._box.pack_end(self._player_toolbar, False, False, 0)
+        self._box.pack_start(self._player_toolbar, False, False, 0)
+        self._box.reorder_child(self._player_toolbar, 1)
 
         self.set_titlebar(self._headerbar_stack)
 
@@ -280,6 +287,10 @@ class Window(Gtk.ApplicationWindow):
         for i in self.views[View.ALBUM:]:
             if i.title:
                 self._stack.add_titled(i, i.name, i.title)
+                self._stack.child_set_property(i, "icon-name", i.icon)
+                i.bind_property("adaptive-view", self, "adaptive-view",
+                                    GObject.BindingFlags.BIDIRECTIONAL
+                                    | GObject.BindingFlags.SYNC_CREATE)
             else:
                 self._stack.add_named(i, i.name)
 
@@ -295,6 +306,10 @@ class Window(Gtk.ApplicationWindow):
             "search-mode-active", self.views[View.ALBUM],
             "search-mode-active", GObject.BindingFlags.SYNC_CREATE)
 
+        # Adaptive View
+        self._switcher_bar.set_stack(self._stack)
+        self.connect("size-allocate", self._on_size_allocate)
+
     @log
     def _select_all(self, action=None, param=None):
         if not self.props.selection_mode:
@@ -487,8 +502,17 @@ class Window(Gtk.ApplicationWindow):
 
         views_with_child = [
             self.views[View.ALBUM],
-            self.views[View.SEARCH]
+            self.views[View.SEARCH],
         ]
+
+        is_folded_childs = [
+            self.views[View.ARTIST],
+            self.views[View.PLAYLIST],
+        ]
+        for child in is_folded_childs:
+            if child.is_folded:
+                views_with_child.append(child)
+
         if self.curr_view in views_with_child:
             self.curr_view._back_button_clicked(self.curr_view)
 
@@ -496,7 +520,25 @@ class Window(Gtk.ApplicationWindow):
     def _on_selection_mode_changed(self, widget, data=None):
         if (not self.props.selection_mode
                 and self._player.state == Playback.STOPPED):
-            self._player_toolbar.hide()
+            self._player_toolbar.set_visible_child(False)
+
+    @log
+    def _on_size_allocate(self, widget, allocation):
+        album_view = self.views[View.ALBUM]
+        artists_view = self.views[View.ARTIST]
+
+        if allocation.width < 650:
+            self.props.adaptive_view = AdaptiveViewMode.MOBILE
+            self._headerbar.view = HeaderBar.View.TITLE
+            self._switcher_bar.set_reveal(True)
+        elif allocation.width <= 900:
+            self.props.adaptive_view = AdaptiveViewMode.TABLET
+            self._headerbar.view = HeaderBar.View.NARROW
+            self._switcher_bar.set_reveal(False)
+        else:
+            self._headerbar.view = HeaderBar.View.WIDE
+            self.props.adaptive_view = AdaptiveViewMode.DESKTOP
+            self._switcher_bar.set_reveal(False)
 
     @log
     def _on_add_to_playlist(self, widget):
@@ -516,10 +558,3 @@ class Window(Gtk.ApplicationWindow):
         self.props.selection_mode = False
         playlist_dialog.destroy()
 
-    @log
-    def set_player_visible(self, visible):
-        """Set PlayWidget action visibility
-
-        :param bool visible: actionbar visibility
-        """
-        self._player_toolbar.set_visible(visible)
diff --git a/meson.build b/meson.build
index b0261a5e..6229156b 100644
--- a/meson.build
+++ b/meson.build
@@ -47,6 +47,8 @@ dependency('pygobject-3.0', version: '>= 3.29.1')
 dependency('py3cairo', version: '>= 1.14.0')
 dependency('grilo-0.3', version: '>= 0.3.9')
 dependency('grilo-plugins-0.3', version: '>= 0.3.9')
+dependency('libhandy-0.0', version: '>= 0.0.10')
+
 
 subproject('libgd',
     default_options: [
diff --git a/org.gnome.Music.json b/org.gnome.Music.json
index ebfdf477..416b30ca 100644
--- a/org.gnome.Music.json
+++ b/org.gnome.Music.json
@@ -135,6 +135,20 @@
             ],
             "cleanup": [ "/include" ]
         },
+        {
+            "name": "libhandy",
+            "buildsystem": "meson",
+            "config-opts": [
+               "-Dvapi=false",
+               "-Dtests=false",
+               "-Dexamples=false",
+               "-Dglade_catalog=disabled"
+            ],
+            "sources": [{
+                "type": "git",
+                "url": "https://source.puri.sm/Librem5/libhandy.git";
+            }]
+        },
         {
             "name": "gnome-music",
             "config-opts" : [


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]