Merge lp:~donadigo/appcenter/sorting-headers into lp:~elementary-apps/appcenter/appcenter

Proposed by Adam Bieńkowski
Status: Rejected
Rejected by: David Hewitt
Proposed branch: lp:~donadigo/appcenter/sorting-headers
Merge into: lp:~elementary-apps/appcenter/appcenter
Diff against target: 432 lines (+146/-213)
2 files modified
src/Views/AppListView.vala (+55/-68)
src/Widgets/UpdateHeaderRow.vala (+91/-145)
To merge this branch: bzr merge lp:~donadigo/appcenter/sorting-headers
Reviewer Review Type Date Requested Status
Felipe Escoto (community) Approve
Review via email: mp+317787@code.launchpad.net

Commit message

Simplify sorting headers and comparing rows

Description of the change

This branch simplifies header sorting and comparing rows to sort them also. The branch is a part of drivers-2 branch.

Header assigning is now done within Gtk's native header_func function, rather than having it in sorting rows.

To post a comment you must log in.
Revision history for this message
Jeremy Wootten (jeremywootten) wrote :

I notice that, when running "Update all", "Searching for updates" and its spinner appear before installation of updates has completed, on a line below the applications being updated. Is this intended? It looks a bit odd.

Revision history for this message
Felipe Escoto (philip.scott) wrote :

The searching for updates still shows on master, so i'm merging it since it just shouldn't appear

review: Approve
Revision history for this message
RabbitBot (rabbitbot-a) wrote :

Attempt to merge into lp:appcenter failed due to conflicts:

text conflict in src/Views/AppListView.vala
text conflict in src/Widgets/UpdateHeaderRow.vala

Revision history for this message
David Hewitt (davidmhewitt) wrote :

This functionality has been merged into the GitHub repository of AppCenter. Closing.

Unmerged revisions

406. By Adam Bieńkowski

Do not remove the update button from the size group

405. By Adam Bieńkowski

Simplify comparing rows and assigning headers for them

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/Views/AppListView.vala'
--- src/Views/AppListView.vala 2017-02-15 18:02:21 +0000
+++ src/Views/AppListView.vala 2017-02-20 17:20:45 +0000
@@ -86,9 +86,7 @@
86 * Does not show Uninstall Button **/86 * Does not show Uninstall Button **/
87 public class AppListUpdateView : AbstractAppList {87 public class AppListUpdateView : AbstractAppList {
88 private bool updates_on_top;88 private bool updates_on_top;
89 private Widgets.UpdateHeaderRow updates_header;89 private Widgets.AppActionButton? update_all_button;
90 private Widgets.UpdateHeaderRow updated_header;
91 private Widgets.AppActionButton update_all_button;
92 private bool updating_all_apps = false;90 private bool updating_all_apps = false;
93 private bool apps_remaining_started = false;91 private bool apps_remaining_started = false;
94 private GLib.Mutex update_mutex;92 private GLib.Mutex update_mutex;
@@ -105,7 +103,7 @@
105 set {103 set {
106 if (_updating_cache != value) {104 if (_updating_cache != value) {
107 _updating_cache = value;105 _updating_cache = value;
108 update_headers ();106 list_box.invalidate_headers ();
109 }107 }
110 }108 }
111 }109 }
@@ -113,19 +111,7 @@
113 construct {111 construct {
114 updates_on_top = true;112 updates_on_top = true;
115113
116 update_all_button = new Widgets.AppActionButton (_("Update All"));114 list_box.set_header_func ((Gtk.ListBoxUpdateHeaderFunc) row_update_header);
117 update_all_button.set_suggested_action_header ();
118 update_all_button.clicked.connect (on_update_all);
119 update_all_button.no_show_all = true;
120 action_button_group.add_widget (update_all_button);
121
122 updates_header = new Widgets.UpdateHeaderRow.updates ();
123 updates_header.add_widget (update_all_button);
124
125 updated_header = new Widgets.UpdateHeaderRow.updated ();
126
127 list_box.add (updates_header);
128 list_box.add (updated_header);
129115
130 update_mutex = GLib.Mutex ();116 update_mutex = GLib.Mutex ();
131 apps_to_update = new Gee.LinkedList<AppCenterCore.Package> ();117 apps_to_update = new Gee.LinkedList<AppCenterCore.Package> ();
@@ -137,7 +123,7 @@
137 _updating_cache = true;123 _updating_cache = true;
138 }124 }
139125
140 protected override void after_add_remove_change_row () {update_headers ();}126 protected override void after_add_remove_change_row () { list_box.invalidate_headers (); }
141127
142 protected override Widgets.AppListRow make_row (AppCenterCore.Package package) {128 protected override Widgets.AppListRow make_row (AppCenterCore.Package package) {
143 return (Widgets.AppListRow)(new Widgets.PackageRow.installed (package, action_button_group, false));129 return (Widgets.AppListRow)(new Widgets.PackageRow.installed (package, action_button_group, false));
@@ -145,34 +131,72 @@
145131
146 protected override void on_package_changing (AppCenterCore.Package package, bool is_changing) {132 protected override void on_package_changing (AppCenterCore.Package package, bool is_changing) {
147 base.on_package_changing (package, is_changing);133 base.on_package_changing (package, is_changing);
148 update_all_button.sensitive = packages_changing == 0;134 if (update_all_button != null) {
135 update_all_button.sensitive = packages_changing == 0;
136 }
149 }137 }
150138
151 [CCode (instance_pos = -1)]139 [CCode (instance_pos = -1)]
152 protected override int package_row_compare (Widgets.AppListRow row1, Widgets.AppListRow row2) {140 protected override int package_row_compare (Widgets.AppListRow row1, Widgets.AppListRow row2) {
153 bool a_is_header = !row1.has_package ();
154 bool b_is_header = !row2.has_package ();
155 bool a_has_updates = row1.get_update_available ();
156 bool b_has_updates = row2.get_update_available ();
157
158 if (a_is_header) {
159 return (a_has_updates || !b_has_updates) ? -1 : 1;
160 } else if (b_is_header) {
161 return (b_has_updates || !a_has_updates) ? 1 : -1;
162 }
163
164 bool a_is_os = row1.get_is_os_updates ();141 bool a_is_os = row1.get_is_os_updates ();
165 bool b_is_os = row2.get_is_os_updates ();142 bool b_is_os = row2.get_is_os_updates ();
166143
167 if (a_is_os || b_is_os) { /* OS update row sorts ahead of other update rows */144 if (a_is_os || b_is_os) { /* OS update row sorts ahead of other update rows */
168 return a_is_os ? -1 : 1;145 return a_is_os ? -1 : 1;
169 } else if ((a_has_updates && !b_has_updates) || (!a_has_updates && b_has_updates)) { /* Updates rows sort ahead of updated rows */146 }
147
148 bool a_has_updates = row1.get_update_available ();
149 bool b_has_updates = row2.get_update_available ();
150
151 if ((a_has_updates && !b_has_updates) || (!a_has_updates && b_has_updates)) { /* Updates rows sort ahead of updated rows */
170 return a_has_updates ? -1 : 1;152 return a_has_updates ? -1 : 1;
171 }153 }
172154
173 return row1.get_name_label ().collate (row2.get_name_label ()); /* Else sort in name order */155 return row1.get_name_label ().collate (row2.get_name_label ()); /* Else sort in name order */
174 }156 }
175157
158 [CCode (instance_pos = -1)]
159 private void row_update_header (Widgets.AppListRow row, Widgets.AppListRow? before) {
160 bool update_available = row.get_update_available ();
161 if (before != null && update_available == before.get_update_available ()) {
162 row.set_header (null);
163 return;
164 }
165
166 if (update_available) {
167 var header = new Widgets.UpdatesGrid ();
168
169 uint update_numbers = 0U;
170 uint64 update_real_size = 0ULL;
171 foreach (var package in get_packages ()) {
172 if (package.update_available) {
173 update_numbers++;
174 update_real_size += package.change_information.get_size ();
175 }
176 }
177
178 header.update (update_numbers, update_real_size, updating_cache);
179
180 // Unfortunately the update all button needs to be recreated everytime the header needs to be updated
181 if (!updating_cache && update_numbers > 0) {
182 update_all_button = new Widgets.AppActionButton (_("Update All"));
183 update_all_button.set_suggested_action_header ();
184 update_all_button.clicked.connect (on_update_all);
185 action_button_group.add_widget (update_all_button);
186
187 header.add_widget (update_all_button);
188 }
189
190 header.show_all ();
191 row.set_header (header);
192 } else {
193 var header = new Widgets.UpdatedGrid ();
194 header.update (0, 0, updating_cache);
195 header.show_all ();
196 row.set_header (header);
197 }
198 }
199
176 private void on_update_all () {200 private void on_update_all () {
177 perform_all_updates.begin ();201 perform_all_updates.begin ();
178 }202 }
@@ -278,42 +302,5 @@
278 return GLib.Source.REMOVE;302 return GLib.Source.REMOVE;
279 });303 });
280 }304 }
281
282 private void update_headers () {
283 /* Do not repeatedly update headers while rapidly adding packages to list */
284 schedule_header_update ();
285 }
286
287 uint grid_timeout_id = 0;
288 private void schedule_header_update () {
289 if (grid_timeout_id > 0) {
290 return;
291 }
292
293 grid_timeout_id = GLib.Timeout.add (20, () => {
294 update_updates_grid ();
295 update_updated_grid ();
296 grid_timeout_id = 0;
297 return false;
298 });
299 }
300
301 private void update_updates_grid () {
302 uint update_numbers = 0U;
303 uint64 update_real_size = 0ULL;
304 foreach (var package in get_packages ()) {
305 if (package.update_available) {
306 update_numbers++;
307 update_real_size += package.change_information.get_size ();
308 }
309 }
310
311 updates_header.update (update_numbers, update_real_size, updating_cache);
312 update_all_button.visible = !updating_cache && update_numbers > 0;
313 }
314
315 private void update_updated_grid () {
316 updated_header.update (0, 0, updating_cache);
317 }
318 }305 }
319}306}
320307
=== modified file 'src/Widgets/UpdateHeaderRow.vala'
--- src/Widgets/UpdateHeaderRow.vala 2016-09-17 19:28:03 +0000
+++ src/Widgets/UpdateHeaderRow.vala 2017-02-20 17:20:45 +0000
@@ -19,153 +19,99 @@
19 */19 */
2020
21namespace AppCenter.Widgets {21namespace AppCenter.Widgets {
22 public class UpdateHeaderRow : Gtk.ListBoxRow, AppListRow {22 /** Base class for Grids in Header Rows **/
23 AbstractHeaderGrid grid;23 public abstract class AbstractHeaderGrid : Gtk.Grid {
24 public bool is_updates_header {get; private set;}24 public uint update_numbers {get; protected set; default = 0;}
25 public uint64 update_real_size {get; protected set; default = 0;}
26 public bool is_updating {get; protected set; default = false;}
2527
26 construct {28 construct {
27 set_activatable (false);29 margin = 12;
28 set_selectable (false);30 column_spacing = 12;
29 }31 }
3032
31 public UpdateHeaderRow.updates () {33 protected void store_data (uint _update_numbers, uint64 _update_real_size, bool _is_updating) {
32 grid = new UpdatesGrid ();34 update_numbers = _update_numbers;
33 add (grid);35 update_real_size = _update_real_size;
34 is_updates_header = true;36 is_updating = _is_updating;
35 }
36
37 public UpdateHeaderRow.updated () {
38 grid = new UpdatedGrid ();
39 add (grid);
40 is_updates_header = false;
41 }
42
43 /** AppListRow Interface methods **/
44
45 /** Updates header row reports it has updates in order to sort first in list **/
46 /** Updated header reports it has updates when updating in order to sort first in list **/
47 public bool get_update_available () {
48 return is_updates_header || grid.is_updating;
49 }
50
51 public bool get_is_os_updates () {
52 critical ("Must not attempt to get is_os_update from header row");
53 assert_not_reached ();
54 }
55
56 /* This indicates it is a header row, not a package row */
57 public bool has_package () {return false;}
58
59 public AppCenterCore.Package? get_package () {
60 critical ("Must not attempt to get package from header row");
61 assert_not_reached ();
62 }
63
64 public string get_name_label () {
65 critical ("Must not attempt to get package name from header row");
66 assert_not_reached ();
67 }37 }
6838
69 public void add_widget (Gtk.Widget widget) {39 public void add_widget (Gtk.Widget widget) {
70 grid.add (widget);40 add (widget);
71 }41 }
7242
73 public void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) {43 public abstract void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating);
74 grid.update (_update_numbers, _update_real_size, _is_updating);44 }
75 changed (); /* Triggers resort */45
76 }46 /** Header to show at top of list if there are updates available **/
77 /** ---------------- **/47 public class UpdatesGrid : AbstractHeaderGrid {
7848 private Gtk.Label update_size_label;
79 /** Base class for Grids in Header Rows **/49 private Gtk.Label updates_label;
80 private abstract class AbstractHeaderGrid : Gtk.Grid {50
81 public uint update_numbers {get; protected set; default = 0;}51 construct {
82 public uint64 update_real_size {get; protected set; default = 0;}52 margin_top = 18;
83 public bool is_updating {get; protected set; default = false;}53 updates_label = new Gtk.Label (null);
8454 ((Gtk.Misc) updates_label).xalign = 0;
85 construct {55 updates_label.get_style_context ().add_class ("h4");
86 margin = 12;56 updates_label.hexpand = true;
87 column_spacing = 12;57
88 }58 update_size_label = new Gtk.Label (null);
8959
90 protected void store_data (uint _update_numbers, uint64 _update_real_size, bool _is_updating) {60 add (updates_label);
91 update_numbers = _update_numbers;61 add (update_size_label);
92 update_real_size = _update_real_size;62 }
93 is_updating = _is_updating;63
94 }64 public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) {
9565 store_data (_update_numbers, _update_real_size, _is_updating);
96 public abstract void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating);66
97 }67 if (!is_updating) {
9868 updates_label.label = ngettext ("%u Update Available", "%u Updates Available", update_numbers).printf (update_numbers);
99 /** Header to show at top of list if there are updates available **/69 update_size_label.label = _("Size: %s").printf (GLib.format_size (update_real_size));
100 private class UpdatesGrid : AbstractHeaderGrid {70 if (update_numbers > 0) {
101 private Gtk.Label update_size_label;71 show_all ();
102 private Gtk.Label updates_label;72 } else {
10373 hide ();
104 construct {74 }
105 margin_top = 18;75 } else {
106 updates_label = new Gtk.Label (null);76 hide (); /* Updated header shows updating spinner and message */
107 ((Gtk.Misc) updates_label).xalign = 0;77 }
108 updates_label.get_style_context ().add_class ("h4");78 }
109 updates_label.hexpand = true;79 }
11080
111 update_size_label = new Gtk.Label (null);81 /** Header to show above first package that is up to date, or if the cache is updating **/
11282 public class UpdatedGrid : AbstractHeaderGrid {
113 add (updates_label);83 private Gtk.Label label;
114 add (update_size_label);84 private Gtk.Spinner spinner;
115 }85
11686 construct {
117 public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) {87 label = new Gtk.Label (""); /* Should not be displayed before being updated */
118 store_data (_update_numbers, _update_real_size, _is_updating);88 label.hexpand = true;
11989 ((Gtk.Misc)label).xalign = 0;
120 if (!is_updating) {90
121 updates_label.label = ngettext ("%u Update Available", "%u Updates Available", update_numbers).printf (update_numbers);91 spinner = new Gtk.Spinner ();
122 update_size_label.label = _("Size: %s").printf (GLib.format_size (update_real_size));92
123 if (update_numbers > 0) {93 add (label);
124 show_all ();94 add (spinner);
125 } else {95 }
126 hide ();96
127 }97 public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) {
128 } else {98 store_data (_update_numbers, _update_real_size, _is_updating);
129 hide (); /* Updated header shows updating spinner and message */99
130 }100 if (is_updating) {
131 }101 halign = Gtk.Align.CENTER;
132 }102 spinner.start ();
133103 spinner.no_show_all = false;
134 /** Header to show above first package that is up to date, or if the cache is updating **/104 spinner.show ();
135 private class UpdatedGrid : AbstractHeaderGrid {105 label.label = _("Searching for updates…");
136 private Gtk.Label label;106 label.get_style_context ().remove_class ("h4");
137 private Gtk.Spinner spinner;107 } else {
138108 halign = Gtk.Align.START;
139 construct {109 spinner.stop ();
140 label = new Gtk.Label (""); /* Should not be displayed before being updated */110 spinner.no_show_all = true;
141 label.hexpand = true;111 spinner.hide ();
142 ((Gtk.Misc)label).xalign = 0;112 label.label = _("Up to Date");
143113 label.get_style_context ().add_class ("h4");
144 spinner = new Gtk.Spinner ();114 }
145115 }
146 add (label);116 }
147 add (spinner);117}
148 }
149
150 public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) {
151 store_data (_update_numbers, _update_real_size, _is_updating);
152
153 if (is_updating) {
154 halign = Gtk.Align.CENTER;
155 spinner.start ();
156 spinner.no_show_all = false;
157 spinner.show ();
158 label.label = _("Searching for updates…");
159 label.get_style_context ().remove_class ("h4");
160 } else {
161 halign = Gtk.Align.START;
162 spinner.stop ();
163 spinner.no_show_all = true;
164 spinner.hide ();
165 label.label = _("Up to Date");
166 label.get_style_context ().add_class ("h4");
167 }
168 }
169 }
170 }
171}
172\ No newline at end of file118\ No newline at end of file

Subscribers

People subscribed via source and target branches