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