[gnome-games] collection-view: Add CollectionsPage



commit 897920c2c1b0ffca56c4f491a8881118767d36e5
Author: Neville <nevilleantony98 gmail com>
Date:   Fri Jul 10 18:50:13 2020 +0530

    collection-view: Add CollectionsPage
    
    CollectionsPage shows available collections. It now supports favorite
    collections. Users can mark/unmark games as favorite.

 data/ui/collection-view.ui     | 502 +++++++++++++++++++++++++----------------
 src/ui/application-window.vala |   6 +-
 src/ui/application.vala        |  13 +-
 src/ui/collection-view.vala    | 126 +++++++++--
 4 files changed, 439 insertions(+), 208 deletions(-)
---
diff --git a/data/ui/collection-view.ui b/data/ui/collection-view.ui
index 220f18f6..8c194d81 100644
--- a/data/ui/collection-view.ui
+++ b/data/ui/collection-view.ui
@@ -16,197 +16,287 @@
         <property name="visible">True</property>
         <property name="transition-type">crossfade</property>
         <child>
-          <object class="HdyDeck" id="deck">
+          <object class="HdyDeck" id="deck_stack">
             <property name="visible">True</property>
-            <property name="can-swipe-back">True</property>
-            <child>
-              <object class="HdyHeaderBar" id="header_bar">
-                <property name="visible">True</property>
-                <property name="show-close-button">True</property>
-                <property name="centering-policy">strict</property>
-                <child>
-                  <object class="GtkButton" id="add_game">
-                    <property name="visible">True</property>
-                    <property name="valign">center</property>
-                    <property name="action-name">app.add-game-files</property>
-                    <style>
-                      <class name="image-button"/>
-                    </style>
-                    <child internal-child="accessible">
-                      <object class="AtkObject" id="a11y-back">
-                        <property name="accessible-name" translatable="yes">Add game files…</property>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImage" id="add_game_image">
-                        <property name="visible">True</property>
-                        <property name="icon-name">list-add-symbolic</property>
-                        <property name="icon-size">1</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="pack-type">start</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkMenuButton" id="menu">
-                    <property name="menu-model">primary_menu</property>
-                    <!-- Translators: tooltip for the application menu button -->
-                    <property name="tooltip-text" translatable="yes">Menu</property>
-                    <property name="valign">center</property>
-                    <property name="visible">True</property>
-                    <style>
-                      <class name="image-button"/>
-                    </style>
-                    <child>
-                      <object class="GtkImage" id="menu_image">
-                        <property name="visible">True</property>
-                        <property name="icon-name">open-menu-symbolic</property>
-                        <property name="icon-size">1</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="pack-type">end</property>
-                  </packing>
-                </child>
-                <child type="title">
-                  <object class="HdyViewSwitcherTitle" id="view_switcher_title">
-                    <property name="visible">True</property>
-                    <property name="title" translatable="yes">Games</property>
-                    <property name="stack">viewstack</property>
-                    <property name="view-switcher-enabled" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|sync-create|invert-boolean"/>
-                    <signal name="notify::title-visible" handler="update_adaptive_state"/>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkButton" id="selection_button">
-                    <property name="visible" bind-source="GamesCollectionView" 
bind-property="is_selection_available" bind-flags="bidirectional"/>
-                    <property name="valign">center</property>
-                    <property name="action-name">view.toggle-select</property>
-                    <property name="sensitive" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|invert-boolean"/>
-                    <child>
-                      <object class="GtkImage" id="select_image">
-                        <property name="visible">True</property>
-                        <property name="icon-name">object-select-symbolic</property>
-                      </object>
-                    </child>
-                    <child internal-child="accessible">
-                      <object class="AtkObject">
-                        <property name="accessible-name" translatable="yes">Select games</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="pack-type">end</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToggleButton" id="search">
-                    <property name="visible">True</property>
-                    <property name="valign">center</property>
-                    <property name="active" bind-source="GamesCollectionView" bind-property="search-mode" 
bind-flags="bidirectional"/>
-                    <property name="sensitive" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|invert-boolean"/>
-                    <style>
-                      <class name="image-button"/>
-                    </style>
-                    <child internal-child="accessible">
-                      <object class="AtkObject" id="a11y-search">
-                        <property name="accessible-name" translatable="yes">Search</property>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImage" id="search_image">
-                        <property name="visible">True</property>
-                        <property name="icon-name">edit-find-symbolic</property>
-                        <property name="icon-size">1</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="pack-type">end</property>
-                  </packing>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="HdyHeaderBar" id="subview_header_bar">
-                <property name="visible">True</property>
-                <property name="show_close_button">True</property>
-                <property name="title" bind-source="platforms_page" bind-property="subview-title"/>
-                <child>
-                  <object class="GtkButton">
-                    <property name="visible">True</property>
-                    <property name="valign">center</property>
-                    <signal name="clicked" handler="on_subview_back_clicked"/>
-                    <style>
-                      <class name="image-button"/>
-                    </style>
-                    <child internal-child="accessible">
-                      <object class="AtkObject">
-                        <property name="accessible-name" translatable="yes">Back</property>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">True</property>
-                        <property name="icon-name">go-previous-symbolic</property>
-                        <property name="icon-size">1</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkButton" id="subview_selection_button">
-                    <property name="visible">True</property>
-                    <property name="valign">center</property>
-                    <property name="sensitive" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|invert-boolean"/>
-                    <property name="action-name">view.toggle-select</property>"
-                    <child>
-                      <object class="GtkImage" id="subview_select_image">
-                        <property name="visible">True</property>
-                        <property name="icon-name">object-select-symbolic</property>
-                      </object>
-                    </child>
-                    <child internal-child="accessible">
-                      <object class="AtkObject">
-                        <property name="accessible-name" translatable="yes">Select games</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="pack-type">end</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToggleButton" id="search_subview">
-                    <property name="visible">True</property>
-                    <property name="valign">center</property>
-                    <property name="active" bind-source="GamesCollectionView" bind-property="search-mode" 
bind-flags="bidirectional"/>
-                    <property name="sensitive" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|invert-boolean"/>
-                    <style>
-                      <class name="image-button"/>
-                    </style>
-                    <child internal-child="accessible">
-                      <object class="AtkObject">
-                        <property name="accessible-name" translatable="yes">Search</property>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">True</property>
-                        <property name="icon-name">edit-find-symbolic</property>
-                        <property name="icon-size">1</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="pack-type">end</property>
-                  </packing>
-                </child>
-              </object>
-            </child>
+              <child>
+                <object class="HdyDeck" id="deck">
+                  <property name="visible">True</property>
+                  <property name="can-swipe-back">True</property>
+                  <child>
+                    <object class="HdyHeaderBar" id="header_bar">
+                      <property name="visible">True</property>
+                      <property name="show-close-button">True</property>
+                      <property name="centering-policy">strict</property>
+                      <child>
+                        <object class="GtkButton" id="add_game">
+                          <property name="visible" bind-source="GamesCollectionView" 
bind-property="is-search-available"/>
+                          <property name="valign">center</property>
+                          <property name="action-name">app.add-game-files</property>
+                          <style>
+                            <class name="image-button"/>
+                          </style>
+                          <child internal-child="accessible">
+                            <object class="AtkObject" id="a11y-back">
+                              <property name="accessible-name" translatable="yes">Add game files…</property>
+                            </object>
+                          </child>
+                          <child>
+                            <object class="GtkImage" id="add_game_image">
+                              <property name="visible">True</property>
+                              <property name="icon-name">list-add-symbolic</property>
+                              <property name="icon-size">1</property>
+                            </object>
+                          </child>
+                        </object>
+                        <packing>
+                          <property name="pack-type">start</property>
+                        </packing>
+                      </child>
+                      <child>
+                        <object class="GtkMenuButton" id="menu">
+                          <property name="menu-model">primary_menu</property>
+                          <!-- Translators: tooltip for the application menu button -->
+                          <property name="tooltip-text" translatable="yes">Menu</property>
+                          <property name="valign">center</property>
+                          <property name="visible">True</property>
+                          <style>
+                            <class name="image-button"/>
+                          </style>
+                          <child>
+                            <object class="GtkImage" id="menu_image">
+                              <property name="visible">True</property>
+                              <property name="icon-name">open-menu-symbolic</property>
+                              <property name="icon-size">1</property>
+                            </object>
+                          </child>
+                        </object>
+                        <packing>
+                          <property name="pack-type">end</property>
+                        </packing>
+                      </child>
+                      <child type="title">
+                        <object class="HdyViewSwitcherTitle" id="view_switcher_title">
+                          <property name="visible">True</property>
+                          <property name="title" translatable="yes">Games</property>
+                          <property name="stack">viewstack</property>
+                          <property name="view-switcher-enabled" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|sync-create|invert-boolean"/>
+                          <signal name="notify::title-visible" handler="update_adaptive_state"/>
+                        </object>
+                      </child>
+                      <child>
+                        <object class="GtkButton" id="selection_button">
+                          <property name="visible" bind-source="GamesCollectionView" 
bind-property="is_selection_available" bind-flags="bidirectional"/>
+                          <property name="valign">center</property>
+                          <property name="action-name">view.toggle-select</property>
+                          <property name="sensitive" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|invert-boolean"/>
+                          <child>
+                            <object class="GtkImage" id="select_image">
+                              <property name="visible">True</property>
+                              <property name="icon-name">object-select-symbolic</property>
+                            </object>
+                          </child>
+                          <child internal-child="accessible">
+                            <object class="AtkObject">
+                              <property name="accessible-name" translatable="yes">Select games</property>
+                            </object>
+                          </child>
+                        </object>
+                        <packing>
+                          <property name="pack-type">end</property>
+                        </packing>
+                      </child>
+                      <child>
+                        <object class="GtkToggleButton" id="search">
+                          <property name="visible" bind-source="GamesCollectionView" 
bind-property="is-search-available"/>
+                          <property name="valign">center</property>
+                          <property name="active" bind-source="GamesCollectionView" 
bind-property="search-mode" bind-flags="bidirectional"/>
+                          <property name="sensitive" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|invert-boolean"/>
+                          <style>
+                            <class name="image-button"/>
+                          </style>
+                          <child internal-child="accessible">
+                            <object class="AtkObject" id="a11y-search">
+                              <property name="accessible-name" translatable="yes">Search</property>
+                            </object>
+                          </child>
+                          <child>
+                            <object class="GtkImage" id="search_image">
+                              <property name="visible">True</property>
+                              <property name="icon-name">edit-find-symbolic</property>
+                              <property name="icon-size">1</property>
+                            </object>
+                          </child>
+                        </object>
+                        <packing>
+                          <property name="pack-type">end</property>
+                        </packing>
+                      </child>
+                    </object>
+                  </child>
+                  <child>
+                    <object class="HdyHeaderBar" id="subview_header_bar">
+                      <property name="visible">True</property>
+                      <property name="show_close_button">True</property>
+                      <property name="title" bind-source="platforms_page" bind-property="subview-title"/>
+                      <child>
+                        <object class="GtkButton">
+                          <property name="visible">True</property>
+                          <property name="valign">center</property>
+                          <signal name="clicked" handler="on_subview_back_clicked"/>
+                          <style>
+                            <class name="image-button"/>
+                          </style>
+                          <child internal-child="accessible">
+                            <object class="AtkObject">
+                              <property name="accessible-name" translatable="yes">Back</property>
+                            </object>
+                          </child>
+                          <child>
+                            <object class="GtkImage">
+                              <property name="visible">True</property>
+                              <property name="icon-name">go-previous-symbolic</property>
+                              <property name="icon-size">1</property>
+                            </object>
+                          </child>
+                        </object>
+                      </child>
+                      <child>
+                        <object class="GtkButton" id="subview_selection_button">
+                          <property name="visible">True</property>
+                          <property name="valign">center</property>
+                          <property name="sensitive" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|invert-boolean"/>
+                          <property name="action-name">view.toggle-select</property>"
+                          <child>
+                            <object class="GtkImage" id="subview_select_image">
+                              <property name="visible">True</property>
+                              <property name="icon-name">object-select-symbolic</property>
+                            </object>
+                          </child>
+                          <child internal-child="accessible">
+                            <object class="AtkObject">
+                              <property name="accessible-name" translatable="yes">Select games</property>
+                            </object>
+                          </child>
+                        </object>
+                        <packing>
+                          <property name="pack-type">end</property>
+                        </packing>
+                      </child>
+                      <child>
+                        <object class="GtkToggleButton" id="search_subview">
+                          <property name="visible">True</property>
+                          <property name="valign">center</property>
+                          <property name="active" bind-source="GamesCollectionView" 
bind-property="search-mode" bind-flags="bidirectional"/>
+                          <property name="sensitive" bind-source="GamesCollectionView" 
bind-property="is-collection-empty" bind-flags="bidirectional|invert-boolean"/>
+                          <style>
+                            <class name="image-button"/>
+                          </style>
+                          <child internal-child="accessible">
+                            <object class="AtkObject">
+                              <property name="accessible-name" translatable="yes">Search</property>
+                            </object>
+                          </child>
+                          <child>
+                            <object class="GtkImage">
+                              <property name="visible">True</property>
+                              <property name="icon-name">edit-find-symbolic</property>
+                              <property name="icon-size">1</property>
+                            </object>
+                          </child>
+                        </object>
+                        <packing>
+                          <property name="pack-type">end</property>
+                        </packing>
+                      </child>
+                    </object>
+                  </child>
+                </object>
+              </child>
+              <child>
+                <object class="HdyHeaderBar" id="collection_subpage_header_bar">
+                  <property name="visible">True</property>
+                  <property name="show-close-button">True</property>
+                  <child>
+                    <object class="GtkButton">
+                      <property name="visible">True</property>
+                      <property name="valign">center</property>
+                      <signal name="clicked" handler="on_collection_subpage_back_clicked"/>
+                      <style>
+                        <class name="image-button"/>
+                      </style>
+                      <child internal-child="accessible">
+                        <object class="AtkObject">
+                          <property name="accessible-name" translatable="yes">Back</property>
+                        </object>
+                      </child>
+                      <child>
+                        <object class="GtkImage">
+                          <property name="visible">True</property>
+                          <property name="icon-name">go-previous-symbolic</property>
+                          <property name="icon-size">1</property>
+                        </object>
+                      </child>
+                    </object>
+                  </child>
+                  <child type="title">
+                    <object class="GtkLabel">
+                      <property name="visible">True</property>
+                      <property name="label" bind-source="collections_page" 
bind-property="collection-title"/>
+                      <style>
+                        <class name="title"/>
+                      </style>
+                    </object>
+                  </child>
+                  <child>
+                    <object class="GtkButton">
+                      <property name="visible">True</property>
+                      <property name="valign">center</property>
+                      <property name="action-name">view.toggle-select</property>
+                      <property name="sensitive" bind-source="collections_page" 
bind-property="is-empty-collection" bind-flags="invert-boolean"/>
+                      <child>
+                        <object class="GtkImage">
+                          <property name="visible">True</property>
+                          <property name="icon-name">object-select-symbolic</property>
+                        </object>
+                      </child>
+                      <child internal-child="accessible">
+                        <object class="AtkObject">
+                          <property name="accessible-name" translatable="yes">Select games</property>
+                        </object>
+                      </child>
+                    </object>
+                    <packing>
+                      <property name="pack-type">end</property>
+                    </packing>
+                  </child>
+                  <child>
+                    <object class="GtkToggleButton">
+                      <property name="visible">True</property>
+                      <property name="valign">center</property>
+                      <property name="active" bind-source="GamesCollectionView" bind-property="search-mode" 
bind-flags="bidirectional"/>
+                      <property name="sensitive" bind-source="collections_page" 
bind-property="is-empty-collection" bind-flags="invert-boolean"/>
+                      <style>
+                        <class name="image-button"/>
+                      </style>
+                      <child internal-child="accessible">
+                        <object class="AtkObject">
+                          <property name="accessible-name" translatable="yes">Search</property>
+                        </object>
+                      </child>
+                      <child>
+                        <object class="GtkImage">
+                          <property name="visible">True</property>
+                          <property name="icon-name">edit-find-symbolic</property>
+                          <property name="icon-size">1</property>
+                        </object>
+                      </child>
+                    </object>
+                    <packing>
+                      <property name="pack-type">end</property>
+                    </packing>
+                  </child>
+                </object>
+              </child>
           </object>
         </child>
         <child>
@@ -334,6 +424,7 @@
                     <property name="visible">True</property>
                     <property name="is-selection-mode" bind-source="GamesCollectionView" 
bind-property="is-selection-mode"/>
                     <signal name="game-activated" handler="on_game_activated"/>
+                    <signal name="selected-items-changed" handler="update_selection_action_bar"/>
                   </object>
                   <packing>
                     <property name="name">games</property>
@@ -348,6 +439,7 @@
                     <property name="is-selection-mode" bind-source="GamesCollectionView" 
bind-property="is-selection-mode"/>
                     <signal name="game-activated" handler="on_game_activated"/>
                     <signal name="notify::is-subview-open" handler="update_selection_availability"/>
+                    <signal name="selected-items-changed" handler="update_selection_action_bar"/>
                   </object>
                   <packing>
                     <property name="name">platform</property>
@@ -356,6 +448,21 @@
                     <property name="title" translatable="yes">Platforms</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GamesCollectionsPage" id="collections_page">
+                    <property name="visible">True</property>
+                    <property name="is-selection-mode" bind-source="GamesCollectionView" 
bind-property="is-selection-mode"/>
+                    <property name="is-search-mode" bind-source="GamesCollectionView" 
bind-property="search-mode" bind-flags="bidirectional"/>
+                    <signal name="game-activated" handler="on_game_activated"/>
+                    <signal name="selected-items-changed" handler="update_selection_action_bar"/>
+                    <signal name="notify::is-subpage-open" handler="update_bottom_bar"/>
+                  </object>
+                  <packing>
+                    <property name="name">collections</property>
+                    <property name="icon-name">folder-symbolic</property>
+                    <property name="title" translatable="yes">Collections</property>
+                  </packing>
+                </child>
               </object>
             </child>
           </object>
@@ -414,8 +521,23 @@
         <property name="stack">viewstack</property>
       </object>
     </child>
+    <child>
+      <object class="GtkRevealer">
+        <property name="visible">True</property>
+        <property name="reveal-child" bind-source="GamesCollectionView" bind-property="is-selection-mode"/>
+        <property name="transition-type">slide-up</property>
+        <child>
+          <object class="GamesSelectionActionBar" id="selection_action_bar"/>
+        </child>
+      </object>
+    </child>
   </template>
   <object class="HdySwipeGroup" id="swipe_group"/>
+  <object class="HdySwipeGroup" id="collections_swipe_group">
+    <swipeables>
+      <swipeable name="deck_stack"/>
+    </swipeables>
+  </object>
   <menu id="primary_menu">
     <section>
       <item>
diff --git a/src/ui/application-window.vala b/src/ui/application-window.vala
index 6ea48723..efafb361 100644
--- a/src/ui/application-window.vala
+++ b/src/ui/application-window.vala
@@ -58,9 +58,10 @@ private class Games.ApplicationWindow : Hdy.ApplicationWindow {
        private Gtk.ApplicationInhibitFlags inhibit_flags;
 
        public GameModel game_model { get; construct; }
+       public CollectionModel collection_model { get; construct; }
 
-       public ApplicationWindow (Application application, GameModel game_model) {
-               Object (application: application, game_model: game_model);
+       public ApplicationWindow (Application application, GameModel game_model, CollectionModel 
collection_model) {
+               Object (application: application, game_model: game_model, collection_model: collection_model);
 
                current_view = collection_view;
        }
@@ -69,6 +70,7 @@ private class Games.ApplicationWindow : Hdy.ApplicationWindow {
                settings = new Settings ("org.gnome.Games");
 
                collection_view.game_model = game_model;
+               collection_view.collection_model = collection_model;
 
                int width, height;
                settings.get ("window-size", "(ii)", out width, out height);
diff --git a/src/ui/application.vala b/src/ui/application.vala
index 5243d28c..7553822f 100644
--- a/src/ui/application.vala
+++ b/src/ui/application.vala
@@ -16,6 +16,9 @@ public class Games.Application : Gtk.Application {
        private GameModel game_model;
        private CoverLoader cover_loader;
 
+       private CollectionManager collection_manager;
+       private CollectionModel collection_model;
+
        private Manette.Monitor manette_monitor;
 
        private bool tracker_failed;
@@ -292,6 +295,10 @@ public class Games.Application : Gtk.Application {
                        game_collection.game_replaced.connect (game_model.replace_game);
                        game_collection.game_removed.connect (game_model.remove_game);
 
+                       collection_model = new CollectionModel ();
+                       collection_manager = new CollectionManager (database);
+                       collection_manager.collection_added.connect (collection_model.add_collection);
+
                        load_game_list.begin ();
 
                        cover_loader = new CoverLoader ();
@@ -304,7 +311,7 @@ public class Games.Application : Gtk.Application {
                        return;
                }
 
-               window = new ApplicationWindow (this, game_model);
+               window = new ApplicationWindow (this, game_model, collection_model);
                window.destroy.connect (() => {
                        quit_application ();
                });
@@ -559,6 +566,10 @@ public class Games.Application : Gtk.Application {
                return game_collection;
        }
 
+       internal CollectionManager get_collection_manager () {
+               return collection_manager;
+       }
+
        internal CoverLoader get_cover_loader () {
                return cover_loader;
        }
diff --git a/src/ui/collection-view.vala b/src/ui/collection-view.vala
index e38a85d4..a135eeba 100644
--- a/src/ui/collection-view.vala
+++ b/src/ui/collection-view.vala
@@ -9,6 +9,8 @@ private class Games.CollectionView : Gtk.Box, UiView {
        [GtkChild]
        private Hdy.Deck deck;
        [GtkChild]
+       private Hdy.Deck deck_stack;
+       [GtkChild]
        private Gtk.Stack header_bar_stack;
        [GtkChild]
        private Hdy.HeaderBar header_bar;
@@ -31,6 +33,12 @@ private class Games.CollectionView : Gtk.Box, UiView {
        [GtkChild]
        private PlatformsPage platforms_page;
        [GtkChild]
+       private CollectionsPage collections_page;
+       [GtkChild]
+       private Hdy.HeaderBar collection_subpage_header_bar;
+       [GtkChild]
+       private SelectionActionBar selection_action_bar;
+       [GtkChild]
        private Gtk.Stack empty_stack;
        [GtkChild]
        private Gtk.Stack viewstack;
@@ -38,6 +46,8 @@ private class Games.CollectionView : Gtk.Box, UiView {
        private Hdy.ViewSwitcherBar view_switcher_bar;
        [GtkChild]
        private Hdy.SwipeGroup swipe_group;
+       [GtkChild]
+       private Hdy.SwipeGroup collections_swipe_group;
 
        private bool _is_view_active;
        public bool is_view_active {
@@ -77,6 +87,7 @@ private class Games.CollectionView : Gtk.Box, UiView {
 
                        platforms_page.set_filter (filtering_terms);
                        games_page.set_filter (filtering_terms);
+                       collections_page.set_filter (filtering_terms);
                }
        }
 
@@ -98,28 +109,41 @@ private class Games.CollectionView : Gtk.Box, UiView {
                }
        }
 
+       public CollectionModel collection_model {
+               get { return collections_page.collection_model; }
+               set {
+                       collections_page.collection_model = value;
+               }
+       }
+
        public bool loading_notification { get; set; }
        public bool search_mode { get; set; }
 
        public bool is_folded { get; set; }
+       public bool is_search_available { get; set; }
        public bool is_showing_bottom_bar { get; set; }
        public bool is_subview_open { get; set; }
        public bool is_selection_mode { get; set; }
        public bool is_selection_available { get; set; }
 
+       private CollectionManager collection_manager;
        private KonamiCode konami_code;
        private SimpleActionGroup action_group;
        private const ActionEntry[] action_entries = {
-               { "select-all",    select_all },
-               { "select-none",   select_none },
-               { "toggle-select", toggle_select }
+               { "select-all",      select_all },
+               { "select-none",     select_none },
+               { "toggle-select",   toggle_select },
+               { "favorite-action", favorite_action }
        };
 
        construct {
+               collection_manager = Application.get_default ().get_collection_manager ();
+
                var icon_name = Config.APPLICATION_ID + "-symbolic";
                viewstack.child_set (games_page, "icon-name", icon_name);
 
                swipe_group.add_swipeable (platforms_page.get_leaflet ());
+               collections_swipe_group.add_swipeable (collections_page.get_collections_deck ());
 
                konami_code = new KonamiCode (window);
                konami_code.code_performed.connect (on_konami_code_performed);
@@ -127,6 +151,8 @@ private class Games.CollectionView : Gtk.Box, UiView {
                action_group = new SimpleActionGroup ();
                action_group.add_action_entries (action_entries, this);
                window.insert_action_group ("view", action_group);
+
+               update_search_availablity ();
        }
 
        public void show_error (string error_message) {
@@ -149,12 +175,17 @@ private class Games.CollectionView : Gtk.Box, UiView {
                    (((window.get_direction () == Gtk.TextDirection.LTR) && keyval == Gdk.Key.Left) ||
                     ((window.get_direction () == Gtk.TextDirection.RTL) && keyval == Gdk.Key.Right)) &&
                     !is_selection_mode &&
-                    deck.navigate (Hdy.NavigationDirection.BACK))
+                    (deck.navigate (Hdy.NavigationDirection.BACK) ||
+                     collections_page.exit_subpage ())) {
                        return true;
+               }
 
                if ((keyval == Gdk.Key.f || keyval == Gdk.Key.F) &&
                    (event.state & default_modifiers) == Gdk.ModifierType.CONTROL_MASK &&
-                   !is_collection_empty) {
+                   (viewstack.visible_child != collections_page ||
+                    collections_page.is_subpage_open) &&
+                    !collections_page.is_empty_collection &&
+                    !is_collection_empty) {
                        if (!search_mode)
                                search_mode = true;
 
@@ -178,6 +209,12 @@ private class Games.CollectionView : Gtk.Box, UiView {
                        return true;
                }
 
+               if ((viewstack.visible_child == collections_page
+                    && !collections_page.is_subpage_open) ||
+                    is_collection_empty ||
+                    collections_page.is_empty_collection)
+                       return false;
+
                return search_bar.handle_event (event);
        }
 
@@ -197,7 +234,7 @@ private class Games.CollectionView : Gtk.Box, UiView {
 
                switch (button) {
                case EventCode.BTN_TL:
-                       if (is_selection_mode)
+                       if (is_selection_mode || collections_page.is_subpage_open)
                                return true;
 
                        var views = viewstack.get_children ();
@@ -210,7 +247,7 @@ private class Games.CollectionView : Gtk.Box, UiView {
 
                        return true;
                case EventCode.BTN_TR:
-                       if (is_selection_mode)
+                       if (is_selection_mode || collections_page.is_subpage_open)
                                return true;
 
                        var views = viewstack.get_children ();
@@ -225,8 +262,10 @@ private class Games.CollectionView : Gtk.Box, UiView {
                default:
                        if (viewstack.visible_child == platforms_page)
                                return platforms_page.gamepad_button_press_event (event);
-                       else
+                       else if (viewstack.visible_child == games_page)
                                return games_page.gamepad_button_press_event (event);
+                       else
+                               return collections_page.gamepad_button_press_event (event);
                }
        }
 
@@ -239,8 +278,10 @@ private class Games.CollectionView : Gtk.Box, UiView {
 
                if (viewstack.visible_child == platforms_page)
                        return platforms_page.gamepad_button_release_event (event);
-               else
+               else if (viewstack.visible_child == games_page)
                        return games_page.gamepad_button_release_event (event);
+               else
+                       return collections_page.gamepad_button_release_event (event);
        }
 
        public bool gamepad_absolute_axis_event (Manette.Event event) {
@@ -252,8 +293,10 @@ private class Games.CollectionView : Gtk.Box, UiView {
 
                if (viewstack.visible_child == platforms_page)
                        return platforms_page.gamepad_absolute_axis_event (event);
-               else
+               else if (viewstack.visible_child == games_page)
                        return games_page.gamepad_absolute_axis_event (event);
+               else
+                       return collections_page.gamepad_absolute_axis_event (event);
        }
 
        private void on_konami_code_performed () {
@@ -268,6 +311,10 @@ private class Games.CollectionView : Gtk.Box, UiView {
                }
        }
 
+       public void update_search_availablity () {
+               is_search_available = viewstack.visible_child != collections_page;
+       }
+
        public void run_search (string query) {
                search_mode = true;
                search_bar.run_search (query);
@@ -276,27 +323,70 @@ private class Games.CollectionView : Gtk.Box, UiView {
        private void select_none () {
                platforms_page.select_none ();
                games_page.select_none ();
+               collections_page.select_none ();
        }
 
        private void select_all () {
                if (viewstack.visible_child == platforms_page)
                        platforms_page.select_all ();
-               else
+               else if (viewstack.visible_child == games_page)
                        games_page.select_all ();
+               else
+                       collections_page.select_all ();
        }
 
        private void toggle_select () {
                is_selection_mode = !is_selection_mode;
        }
 
+       private void favorite_action () {
+               if (viewstack.visible_child == games_page)
+                       collection_manager.toggle_favorite (games_page.get_selected_games ());
+               else if (viewstack.visible_child == platforms_page)
+                       collection_manager.toggle_favorite (platforms_page.get_selected_games ());
+               else {
+                       collection_manager.toggle_favorite (collections_page.get_selected_games ());
+
+                       collections_page.update_is_empty_collection ();
+                       select_none ();
+                       toggle_select ();
+
+                       return;
+               }
+
+               update_selection_action_bar ();
+       }
+
+       [GtkCallback]
+       private void update_selection_action_bar () {
+               Game[] games = {};
+               if (viewstack.visible_child == games_page)
+                       games = games_page.get_selected_games ();
+               else if (viewstack.visible_child == platforms_page)
+                       games = platforms_page.get_selected_games ();
+
+               selection_action_bar.update (games);
+       }
+
+       [GtkCallback]
+       private void on_collection_subpage_back_clicked () {
+               collections_page.exit_subpage ();
+       }
+
        [GtkCallback]
        private void on_selection_mode_changed () {
                if (is_selection_mode) {
                        header_bar_stack.visible_child = selection_mode_header_bar;
+
+                       selection_action_bar.favorite_state = SelectionActionBar.FavoriteState.NONE_FAVORITE;
                }
                else {
                        select_none ();
-                       header_bar_stack.visible_child = deck;
+                       header_bar_stack.visible_child = deck_stack;
+                       if (collections_page.is_subpage_open)
+                               deck_stack.visible_child = collection_subpage_header_bar;
+                       else
+                               deck_stack.visible_child = deck;
                }
 
                update_bottom_bar ();
@@ -310,7 +400,8 @@ private class Games.CollectionView : Gtk.Box, UiView {
 
        [GtkCallback]
        private void update_selection_availability () {
-               is_selection_available = viewstack.visible_child != platforms_page || !is_folded;
+               is_selection_available = (viewstack.visible_child != platforms_page || !is_folded)
+                                        && viewstack.visible_child != collections_page;
        }
 
        [GtkCallback]
@@ -327,10 +418,13 @@ private class Games.CollectionView : Gtk.Box, UiView {
        private void on_visible_child_changed () {
                if (viewstack.visible_child == games_page)
                        games_page.reset_scroll_position ();
-               else
+               else if (viewstack.visible_child == platforms_page)
                        platforms_page.reset ();
+               else
+                       collections_page.reset_scroll_position ();
 
                update_selection_availability ();
+               update_search_availablity ();
        }
 
        [GtkCallback]
@@ -371,12 +465,14 @@ private class Games.CollectionView : Gtk.Box, UiView {
 
                update_bottom_bar ();
                update_selection_availability ();
+               update_search_availablity ();
        }
 
        [GtkCallback]
        private void update_bottom_bar () {
                view_switcher_bar.reveal = !is_selection_mode && is_showing_bottom_bar
-                                          && (!is_folded || !is_subview_open);
+                                          && (!is_folded || !is_subview_open)
+                                          && !collections_page.is_subpage_open;
        }
 
        [GtkCallback]



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