Merge lp:~donadigo/appcenter/sorting-headers into lp:~elementary-apps/appcenter/appcenter
- sorting-headers
- Merge into 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 |
Related bugs: |
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 : | # |
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/
text conflict in src/Widgets/
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
1 | === modified file 'src/Views/AppListView.vala' |
2 | --- src/Views/AppListView.vala 2017-02-15 18:02:21 +0000 |
3 | +++ src/Views/AppListView.vala 2017-02-20 17:20:45 +0000 |
4 | @@ -86,9 +86,7 @@ |
5 | * Does not show Uninstall Button **/ |
6 | public class AppListUpdateView : AbstractAppList { |
7 | private bool updates_on_top; |
8 | - private Widgets.UpdateHeaderRow updates_header; |
9 | - private Widgets.UpdateHeaderRow updated_header; |
10 | - private Widgets.AppActionButton update_all_button; |
11 | + private Widgets.AppActionButton? update_all_button; |
12 | private bool updating_all_apps = false; |
13 | private bool apps_remaining_started = false; |
14 | private GLib.Mutex update_mutex; |
15 | @@ -105,7 +103,7 @@ |
16 | set { |
17 | if (_updating_cache != value) { |
18 | _updating_cache = value; |
19 | - update_headers (); |
20 | + list_box.invalidate_headers (); |
21 | } |
22 | } |
23 | } |
24 | @@ -113,19 +111,7 @@ |
25 | construct { |
26 | updates_on_top = true; |
27 | |
28 | - update_all_button = new Widgets.AppActionButton (_("Update All")); |
29 | - update_all_button.set_suggested_action_header (); |
30 | - update_all_button.clicked.connect (on_update_all); |
31 | - update_all_button.no_show_all = true; |
32 | - action_button_group.add_widget (update_all_button); |
33 | - |
34 | - updates_header = new Widgets.UpdateHeaderRow.updates (); |
35 | - updates_header.add_widget (update_all_button); |
36 | - |
37 | - updated_header = new Widgets.UpdateHeaderRow.updated (); |
38 | - |
39 | - list_box.add (updates_header); |
40 | - list_box.add (updated_header); |
41 | + list_box.set_header_func ((Gtk.ListBoxUpdateHeaderFunc) row_update_header); |
42 | |
43 | update_mutex = GLib.Mutex (); |
44 | apps_to_update = new Gee.LinkedList<AppCenterCore.Package> (); |
45 | @@ -137,7 +123,7 @@ |
46 | _updating_cache = true; |
47 | } |
48 | |
49 | - protected override void after_add_remove_change_row () {update_headers ();} |
50 | + protected override void after_add_remove_change_row () { list_box.invalidate_headers (); } |
51 | |
52 | protected override Widgets.AppListRow make_row (AppCenterCore.Package package) { |
53 | return (Widgets.AppListRow)(new Widgets.PackageRow.installed (package, action_button_group, false)); |
54 | @@ -145,34 +131,72 @@ |
55 | |
56 | protected override void on_package_changing (AppCenterCore.Package package, bool is_changing) { |
57 | base.on_package_changing (package, is_changing); |
58 | - update_all_button.sensitive = packages_changing == 0; |
59 | + if (update_all_button != null) { |
60 | + update_all_button.sensitive = packages_changing == 0; |
61 | + } |
62 | } |
63 | |
64 | [CCode (instance_pos = -1)] |
65 | protected override int package_row_compare (Widgets.AppListRow row1, Widgets.AppListRow row2) { |
66 | - bool a_is_header = !row1.has_package (); |
67 | - bool b_is_header = !row2.has_package (); |
68 | - bool a_has_updates = row1.get_update_available (); |
69 | - bool b_has_updates = row2.get_update_available (); |
70 | - |
71 | - if (a_is_header) { |
72 | - return (a_has_updates || !b_has_updates) ? -1 : 1; |
73 | - } else if (b_is_header) { |
74 | - return (b_has_updates || !a_has_updates) ? 1 : -1; |
75 | - } |
76 | - |
77 | bool a_is_os = row1.get_is_os_updates (); |
78 | bool b_is_os = row2.get_is_os_updates (); |
79 | |
80 | if (a_is_os || b_is_os) { /* OS update row sorts ahead of other update rows */ |
81 | return a_is_os ? -1 : 1; |
82 | - } else if ((a_has_updates && !b_has_updates) || (!a_has_updates && b_has_updates)) { /* Updates rows sort ahead of updated rows */ |
83 | + } |
84 | + |
85 | + bool a_has_updates = row1.get_update_available (); |
86 | + bool b_has_updates = row2.get_update_available (); |
87 | + |
88 | + if ((a_has_updates && !b_has_updates) || (!a_has_updates && b_has_updates)) { /* Updates rows sort ahead of updated rows */ |
89 | return a_has_updates ? -1 : 1; |
90 | } |
91 | |
92 | return row1.get_name_label ().collate (row2.get_name_label ()); /* Else sort in name order */ |
93 | } |
94 | |
95 | + [CCode (instance_pos = -1)] |
96 | + private void row_update_header (Widgets.AppListRow row, Widgets.AppListRow? before) { |
97 | + bool update_available = row.get_update_available (); |
98 | + if (before != null && update_available == before.get_update_available ()) { |
99 | + row.set_header (null); |
100 | + return; |
101 | + } |
102 | + |
103 | + if (update_available) { |
104 | + var header = new Widgets.UpdatesGrid (); |
105 | + |
106 | + uint update_numbers = 0U; |
107 | + uint64 update_real_size = 0ULL; |
108 | + foreach (var package in get_packages ()) { |
109 | + if (package.update_available) { |
110 | + update_numbers++; |
111 | + update_real_size += package.change_information.get_size (); |
112 | + } |
113 | + } |
114 | + |
115 | + header.update (update_numbers, update_real_size, updating_cache); |
116 | + |
117 | + // Unfortunately the update all button needs to be recreated everytime the header needs to be updated |
118 | + if (!updating_cache && update_numbers > 0) { |
119 | + update_all_button = new Widgets.AppActionButton (_("Update All")); |
120 | + update_all_button.set_suggested_action_header (); |
121 | + update_all_button.clicked.connect (on_update_all); |
122 | + action_button_group.add_widget (update_all_button); |
123 | + |
124 | + header.add_widget (update_all_button); |
125 | + } |
126 | + |
127 | + header.show_all (); |
128 | + row.set_header (header); |
129 | + } else { |
130 | + var header = new Widgets.UpdatedGrid (); |
131 | + header.update (0, 0, updating_cache); |
132 | + header.show_all (); |
133 | + row.set_header (header); |
134 | + } |
135 | + } |
136 | + |
137 | private void on_update_all () { |
138 | perform_all_updates.begin (); |
139 | } |
140 | @@ -278,42 +302,5 @@ |
141 | return GLib.Source.REMOVE; |
142 | }); |
143 | } |
144 | - |
145 | - private void update_headers () { |
146 | - /* Do not repeatedly update headers while rapidly adding packages to list */ |
147 | - schedule_header_update (); |
148 | - } |
149 | - |
150 | - uint grid_timeout_id = 0; |
151 | - private void schedule_header_update () { |
152 | - if (grid_timeout_id > 0) { |
153 | - return; |
154 | - } |
155 | - |
156 | - grid_timeout_id = GLib.Timeout.add (20, () => { |
157 | - update_updates_grid (); |
158 | - update_updated_grid (); |
159 | - grid_timeout_id = 0; |
160 | - return false; |
161 | - }); |
162 | - } |
163 | - |
164 | - private void update_updates_grid () { |
165 | - uint update_numbers = 0U; |
166 | - uint64 update_real_size = 0ULL; |
167 | - foreach (var package in get_packages ()) { |
168 | - if (package.update_available) { |
169 | - update_numbers++; |
170 | - update_real_size += package.change_information.get_size (); |
171 | - } |
172 | - } |
173 | - |
174 | - updates_header.update (update_numbers, update_real_size, updating_cache); |
175 | - update_all_button.visible = !updating_cache && update_numbers > 0; |
176 | - } |
177 | - |
178 | - private void update_updated_grid () { |
179 | - updated_header.update (0, 0, updating_cache); |
180 | - } |
181 | } |
182 | } |
183 | |
184 | === modified file 'src/Widgets/UpdateHeaderRow.vala' |
185 | --- src/Widgets/UpdateHeaderRow.vala 2016-09-17 19:28:03 +0000 |
186 | +++ src/Widgets/UpdateHeaderRow.vala 2017-02-20 17:20:45 +0000 |
187 | @@ -19,153 +19,99 @@ |
188 | */ |
189 | |
190 | namespace AppCenter.Widgets { |
191 | - public class UpdateHeaderRow : Gtk.ListBoxRow, AppListRow { |
192 | - AbstractHeaderGrid grid; |
193 | - public bool is_updates_header {get; private set;} |
194 | + /** Base class for Grids in Header Rows **/ |
195 | + public abstract class AbstractHeaderGrid : Gtk.Grid { |
196 | + public uint update_numbers {get; protected set; default = 0;} |
197 | + public uint64 update_real_size {get; protected set; default = 0;} |
198 | + public bool is_updating {get; protected set; default = false;} |
199 | |
200 | construct { |
201 | - set_activatable (false); |
202 | - set_selectable (false); |
203 | - } |
204 | - |
205 | - public UpdateHeaderRow.updates () { |
206 | - grid = new UpdatesGrid (); |
207 | - add (grid); |
208 | - is_updates_header = true; |
209 | - } |
210 | - |
211 | - public UpdateHeaderRow.updated () { |
212 | - grid = new UpdatedGrid (); |
213 | - add (grid); |
214 | - is_updates_header = false; |
215 | - } |
216 | - |
217 | - /** AppListRow Interface methods **/ |
218 | - |
219 | - /** Updates header row reports it has updates in order to sort first in list **/ |
220 | - /** Updated header reports it has updates when updating in order to sort first in list **/ |
221 | - public bool get_update_available () { |
222 | - return is_updates_header || grid.is_updating; |
223 | - } |
224 | - |
225 | - public bool get_is_os_updates () { |
226 | - critical ("Must not attempt to get is_os_update from header row"); |
227 | - assert_not_reached (); |
228 | - } |
229 | - |
230 | - /* This indicates it is a header row, not a package row */ |
231 | - public bool has_package () {return false;} |
232 | - |
233 | - public AppCenterCore.Package? get_package () { |
234 | - critical ("Must not attempt to get package from header row"); |
235 | - assert_not_reached (); |
236 | - } |
237 | - |
238 | - public string get_name_label () { |
239 | - critical ("Must not attempt to get package name from header row"); |
240 | - assert_not_reached (); |
241 | + margin = 12; |
242 | + column_spacing = 12; |
243 | + } |
244 | + |
245 | + protected void store_data (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
246 | + update_numbers = _update_numbers; |
247 | + update_real_size = _update_real_size; |
248 | + is_updating = _is_updating; |
249 | } |
250 | |
251 | public void add_widget (Gtk.Widget widget) { |
252 | - grid.add (widget); |
253 | - } |
254 | - |
255 | - public void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
256 | - grid.update (_update_numbers, _update_real_size, _is_updating); |
257 | - changed (); /* Triggers resort */ |
258 | - } |
259 | - /** ---------------- **/ |
260 | - |
261 | - /** Base class for Grids in Header Rows **/ |
262 | - private abstract class AbstractHeaderGrid : Gtk.Grid { |
263 | - public uint update_numbers {get; protected set; default = 0;} |
264 | - public uint64 update_real_size {get; protected set; default = 0;} |
265 | - public bool is_updating {get; protected set; default = false;} |
266 | - |
267 | - construct { |
268 | - margin = 12; |
269 | - column_spacing = 12; |
270 | - } |
271 | - |
272 | - protected void store_data (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
273 | - update_numbers = _update_numbers; |
274 | - update_real_size = _update_real_size; |
275 | - is_updating = _is_updating; |
276 | - } |
277 | - |
278 | - public abstract void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating); |
279 | - } |
280 | - |
281 | - /** Header to show at top of list if there are updates available **/ |
282 | - private class UpdatesGrid : AbstractHeaderGrid { |
283 | - private Gtk.Label update_size_label; |
284 | - private Gtk.Label updates_label; |
285 | - |
286 | - construct { |
287 | - margin_top = 18; |
288 | - updates_label = new Gtk.Label (null); |
289 | - ((Gtk.Misc) updates_label).xalign = 0; |
290 | - updates_label.get_style_context ().add_class ("h4"); |
291 | - updates_label.hexpand = true; |
292 | - |
293 | - update_size_label = new Gtk.Label (null); |
294 | - |
295 | - add (updates_label); |
296 | - add (update_size_label); |
297 | - } |
298 | - |
299 | - public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
300 | - store_data (_update_numbers, _update_real_size, _is_updating); |
301 | - |
302 | - if (!is_updating) { |
303 | - updates_label.label = ngettext ("%u Update Available", "%u Updates Available", update_numbers).printf (update_numbers); |
304 | - update_size_label.label = _("Size: %s").printf (GLib.format_size (update_real_size)); |
305 | - if (update_numbers > 0) { |
306 | - show_all (); |
307 | - } else { |
308 | - hide (); |
309 | - } |
310 | - } else { |
311 | - hide (); /* Updated header shows updating spinner and message */ |
312 | - } |
313 | - } |
314 | - } |
315 | - |
316 | - /** Header to show above first package that is up to date, or if the cache is updating **/ |
317 | - private class UpdatedGrid : AbstractHeaderGrid { |
318 | - private Gtk.Label label; |
319 | - private Gtk.Spinner spinner; |
320 | - |
321 | - construct { |
322 | - label = new Gtk.Label (""); /* Should not be displayed before being updated */ |
323 | - label.hexpand = true; |
324 | - ((Gtk.Misc)label).xalign = 0; |
325 | - |
326 | - spinner = new Gtk.Spinner (); |
327 | - |
328 | - add (label); |
329 | - add (spinner); |
330 | - } |
331 | - |
332 | - public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
333 | - store_data (_update_numbers, _update_real_size, _is_updating); |
334 | - |
335 | - if (is_updating) { |
336 | - halign = Gtk.Align.CENTER; |
337 | - spinner.start (); |
338 | - spinner.no_show_all = false; |
339 | - spinner.show (); |
340 | - label.label = _("Searching for updates…"); |
341 | - label.get_style_context ().remove_class ("h4"); |
342 | - } else { |
343 | - halign = Gtk.Align.START; |
344 | - spinner.stop (); |
345 | - spinner.no_show_all = true; |
346 | - spinner.hide (); |
347 | - label.label = _("Up to Date"); |
348 | - label.get_style_context ().add_class ("h4"); |
349 | - } |
350 | - } |
351 | - } |
352 | - } |
353 | -} |
354 | + add (widget); |
355 | + } |
356 | + |
357 | + public abstract void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating); |
358 | + } |
359 | + |
360 | + /** Header to show at top of list if there are updates available **/ |
361 | + public class UpdatesGrid : AbstractHeaderGrid { |
362 | + private Gtk.Label update_size_label; |
363 | + private Gtk.Label updates_label; |
364 | + |
365 | + construct { |
366 | + margin_top = 18; |
367 | + updates_label = new Gtk.Label (null); |
368 | + ((Gtk.Misc) updates_label).xalign = 0; |
369 | + updates_label.get_style_context ().add_class ("h4"); |
370 | + updates_label.hexpand = true; |
371 | + |
372 | + update_size_label = new Gtk.Label (null); |
373 | + |
374 | + add (updates_label); |
375 | + add (update_size_label); |
376 | + } |
377 | + |
378 | + public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
379 | + store_data (_update_numbers, _update_real_size, _is_updating); |
380 | + |
381 | + if (!is_updating) { |
382 | + updates_label.label = ngettext ("%u Update Available", "%u Updates Available", update_numbers).printf (update_numbers); |
383 | + update_size_label.label = _("Size: %s").printf (GLib.format_size (update_real_size)); |
384 | + if (update_numbers > 0) { |
385 | + show_all (); |
386 | + } else { |
387 | + hide (); |
388 | + } |
389 | + } else { |
390 | + hide (); /* Updated header shows updating spinner and message */ |
391 | + } |
392 | + } |
393 | + } |
394 | + |
395 | + /** Header to show above first package that is up to date, or if the cache is updating **/ |
396 | + public class UpdatedGrid : AbstractHeaderGrid { |
397 | + private Gtk.Label label; |
398 | + private Gtk.Spinner spinner; |
399 | + |
400 | + construct { |
401 | + label = new Gtk.Label (""); /* Should not be displayed before being updated */ |
402 | + label.hexpand = true; |
403 | + ((Gtk.Misc)label).xalign = 0; |
404 | + |
405 | + spinner = new Gtk.Spinner (); |
406 | + |
407 | + add (label); |
408 | + add (spinner); |
409 | + } |
410 | + |
411 | + public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
412 | + store_data (_update_numbers, _update_real_size, _is_updating); |
413 | + |
414 | + if (is_updating) { |
415 | + halign = Gtk.Align.CENTER; |
416 | + spinner.start (); |
417 | + spinner.no_show_all = false; |
418 | + spinner.show (); |
419 | + label.label = _("Searching for updates…"); |
420 | + label.get_style_context ().remove_class ("h4"); |
421 | + } else { |
422 | + halign = Gtk.Align.START; |
423 | + spinner.stop (); |
424 | + spinner.no_show_all = true; |
425 | + spinner.hide (); |
426 | + label.label = _("Up to Date"); |
427 | + label.get_style_context ().add_class ("h4"); |
428 | + } |
429 | + } |
430 | + } |
431 | +} |
432 | \ No newline at end of file |
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.