Merge lp:~donadigo/appcenter/action-buttons-state into lp:~elementary-apps/appcenter/appcenter

Proposed by Adam Bieńkowski
Status: Merged
Approved by: Danielle Foré
Approved revision: 242
Merged at revision: 243
Proposed branch: lp:~donadigo/appcenter/action-buttons-state
Merge into: lp:~elementary-apps/appcenter/appcenter
Diff against target: 611 lines (+181/-147)
6 files modified
src/Core/ChangeInformation.vala (+1/-4)
src/Core/Client.vala (+12/-6)
src/Core/Package.vala (+70/-25)
src/Views/AppInfoView.vala (+53/-65)
src/Views/AppListView.vala (+1/-1)
src/Widgets/PackageRow.vala (+44/-46)
To merge this branch: bzr merge lp:~donadigo/appcenter/action-buttons-state
Reviewer Review Type Date Requested Status
Corentin Noël code Approve
Danielle Foré Needs Fixing
Review via email: mp+298987@code.launchpad.net

Commit message

- Rework action buttons frontend.
- Fix incorrect action label on update page.
- Remove unneded code.

Description of the change

This branch reworks the current frontend for action buttons.
It now uses it's own enum "Package.State" which reflects the current state. The frontend reads the state and based on it shows available actions.

There are also some other changes to the backend and that's why I would like to have a code and test review first before merging this branch.

It also fixes current incorrect displaying "Install" label on update page.

To post a comment you must log in.
237. By Adam Bieńkowski

Do not show uninstall button for OS updates

Revision history for this message
Corentin Noël (tintou) wrote :

The code looks fine, thank you for this simplification !

review: Approve (code)
Revision history for this message
Danielle Foré (danrabbit) wrote :

Everything seems to work correctly from the appinfo view.

If you install from packagerow, the button state for that package won't update until you perform another installation

review: Needs Fixing
238. By Adam Bieńkowski

Added missing line to PackageRow.vala; remove unneded progress state action_stack setting

239. By Adam Bieńkowski

Remove unneded code

Revision history for this message
Danielle Foré (danrabbit) wrote :

1. Start an uninstall in AppInfo
2. Press back

Expectation: See the uninstall progress in PackageRow
Reality: No progress

review: Needs Fixing
240. By Adam Bieńkowski

Remove unneded action_stack visibility changing in AppInfoView; show action stack in the PackageRow when action in progress

Revision history for this message
Adam Bieńkowski (donadigo) wrote :

Updated.

Revision history for this message
Danielle Foré (danrabbit) wrote :

On the updates tab, after updating a package it no longer re-organizes itself under the "Up to Date" header.

review: Needs Fixing
241. By Adam Bieńkowski

Move state setting after clearing action info

Revision history for this message
Adam Bieńkowski (donadigo) wrote :

Updated again. Just FYI number of available updates doesn't update, but that issue also exists in trunk.

Revision history for this message
Corentin Noël (tintou) wrote :

The code remains good.

review: Approve (code)
Revision history for this message
Cody Garver (codygarver) wrote :

I found a regression in this branch:

When you click Update on Package A, and while it's in progress, click Update on Package B

Package A says Finished when it completes but the progress bar remains and displays 50% until Package B update is complete

In Trunk, the Package A progress bar disappears as soon as Package A update is complete, regardless of the state of Package B

242. By Adam Bieńkowski

Fixed condition where the state could only change if the app was in focus

Revision history for this message
Danielle Foré (danrabbit) wrote :

I can still confirm the issue that Cody pointed out

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Core/ChangeInformation.vala'
2--- src/Core/ChangeInformation.vala 2016-06-29 21:40:17 +0000
3+++ src/Core/ChangeInformation.vala 2016-07-08 20:54:59 +0000
4@@ -26,11 +26,8 @@
5 public Gee.TreeSet<Pk.Details> details { public get; private set; }
6 public bool can_cancel { public get; private set; default=true; }
7 private Gee.HashMap<string, double?> change_progress;
8- public Pk.Status status;
9+ private Pk.Status status;
10 private double progress;
11- public ChangeInformation () {
12-
13- }
14
15 construct {
16 changes = new Gee.TreeSet<Pk.Package> ();
17
18=== modified file 'src/Core/Client.vala'
19--- src/Core/Client.vala 2016-07-01 22:02:04 +0000
20+++ src/Core/Client.vala 2016-07-08 20:54:59 +0000
21@@ -143,7 +143,8 @@
22 return exit_status;
23 }
24
25- public async void update_package (Package package, Pk.ProgressCallback cb, GLib.Cancellable cancellable) throws GLib.Error {
26+ public async Pk.Exit update_package (Package package, Pk.ProgressCallback cb, GLib.Cancellable cancellable) throws GLib.Error {
27+ Pk.Exit exit_status = Pk.Exit.UNKNOWN;
28 SuspendControl sc = new SuspendControl ();
29 AppCenter.Task update_task = request_task ();
30 string[] packages_ids = {};
31@@ -155,7 +156,8 @@
32 try {
33 sc.inhibit ();
34 var results = yield update_task.update_packages_async (packages_ids, cancellable, cb);
35- if (results.get_exit_code () != Pk.Exit.SUCCESS) {
36+ exit_status = results.get_exit_code ();
37+ if (exit_status != Pk.Exit.SUCCESS) {
38 release_task (update_task);
39 throw new GLib.IOError.FAILED (Pk.Exit.enum_to_string (results.get_exit_code ()));
40 }
41@@ -168,9 +170,11 @@
42
43 yield refresh_updates ();
44 release_task (update_task);
45+ return exit_status;
46 }
47
48- public async void remove_package (Package package, Pk.ProgressCallback cb, GLib.Cancellable cancellable) throws GLib.Error {
49+ public async Pk.Exit remove_package (Package package, Pk.ProgressCallback cb, GLib.Cancellable cancellable) throws GLib.Error {
50+ Pk.Exit exit_status = Pk.Exit.UNKNOWN;
51 AppCenter.Task remove_task = request_task ();
52 AppCenter.Task search_task = request_task ();
53 string[] packages_ids = {};
54@@ -187,7 +191,8 @@
55 packages_ids += package.package_id;
56 });
57
58- yield remove_task.remove_packages_async (packages_ids, true, true, cancellable, cb);
59+ results = yield remove_task.remove_packages_async (packages_ids, true, true, cancellable, cb);
60+ exit_status = results.get_exit_code ();
61 } catch (Error e) {
62 release_task (search_task);
63 release_task (remove_task);
64@@ -197,6 +202,7 @@
65 yield refresh_updates ();
66 release_task (search_task);
67 release_task (remove_task);
68+ return exit_status;
69 }
70
71 public async void get_updates () {
72@@ -228,7 +234,7 @@
73
74 package.change_information.changes.add (pk_package);
75 package.change_information.details.add (pk_detail);
76- package.notify_property ("update-available");
77+ package.update_state ();
78 } catch (Error e) {
79 critical (e.message);
80 }
81@@ -252,7 +258,7 @@
82 var package = package_list.get (pk_package.get_name ());
83 if (package != null) {
84 package.installed_packages.add (pk_package);
85- package.notify_property ("installed");
86+ package.update_state ();
87 packages.add (package);
88 }
89 }
90
91=== modified file 'src/Core/Package.vala'
92--- src/Core/Package.vala 2016-07-01 22:02:04 +0000
93+++ src/Core/Package.vala 2016-07-08 20:54:59 +0000
94@@ -19,26 +19,32 @@
95 */
96
97 public class AppCenterCore.Package : Object {
98+ public enum State {
99+ NOT_INSTALLED,
100+ INSTALLED,
101+ INSTALLING,
102+ UPDATE_AVAILABLE,
103+ UPDATING,
104+ REMOVING
105+ }
106+
107 public const string OS_UPDATES_ID = "xxx-os-updates";
108- public signal void changed ();
109
110 public AppStream.Component component { public get; private set; }
111 public ChangeInformation change_information { public get; private set; }
112 public Gee.TreeSet<Pk.Package> installed_packages { public get; private set; }
113 public GLib.Cancellable action_cancellable { public get; private set; }
114- public bool changing { public get; private set; default= false; }
115+ public bool changing { public get; private set; default = false; }
116+ public State state { public get; private set; default = State.NOT_INSTALLED; }
117
118 public bool installed {
119- public get {
120+ get {
121 return !installed_packages.is_empty || component.get_id () == OS_UPDATES_ID;
122 }
123- private set {
124-
125- }
126 }
127
128 public bool update_available {
129- public get {
130+ get {
131 return installed && change_information.has_changes ();
132 }
133 }
134@@ -50,19 +56,40 @@
135 action_cancellable = new GLib.Cancellable ();
136 }
137
138+ public void update_state () {
139+ if (installed) {
140+ if (update_available) {
141+ state = State.UPDATE_AVAILABLE;
142+ } else {
143+ state = State.INSTALLED;
144+ }
145+ } else {
146+ state = State.NOT_INSTALLED;
147+ }
148+ }
149+
150 public async void update () throws GLib.Error {
151 action_cancellable.reset ();
152 changing = true;
153- changed ();
154+
155+ var previous_state = state;
156+ state = State.UPDATING;
157 try {
158- yield AppCenterCore.Client.get_default ().update_package (this, (progress, type) => {change_information.ProgressCallback (progress, type);}, action_cancellable);
159+ var exit_status = yield AppCenterCore.Client.get_default ().update_package (this, (progress, type) => {change_information.ProgressCallback (progress, type);}, action_cancellable);
160 installed_packages.add_all (change_information.changes);
161 change_information.clear ();
162- notify_property ("update-available");
163- changing = false;
164+
165+ if (exit_status == Pk.Exit.SUCCESS) {
166+ state = State.INSTALLED;
167+ } else {
168+ state = previous_state;
169+ }
170+
171+ changing = false;
172 } catch (Error e) {
173 change_information.reset ();
174 changing = false;
175+ state = previous_state;
176 throw e;
177 }
178 }
179@@ -70,28 +97,37 @@
180 public async void install () throws GLib.Error {
181 action_cancellable.reset ();
182 changing = true;
183- changed ();
184+
185+ var previous_state = state;
186+ state = State.INSTALLING;
187 try {
188 var application = (Gtk.Application)Application.get_default ();
189 var window = application.get_active_window ().get_window ();
190
191 var exit_status = yield AppCenterCore.Client.get_default ().install_package (this, (progress, type) => {change_information.ProgressCallback (progress, type);}, action_cancellable);
192- if (exit_status == Pk.Exit.SUCCESS && (window.get_state () & Gdk.WindowState.FOCUSED) == 0) {
193- var notification = new Notification (_("Application installed"));
194- notification.set_body (_("%s has been successfully installed").printf (get_name ()));
195- notification.set_icon (new ThemedIcon ("system-software-install"));
196- notification.set_default_action ("app.open-application");
197-
198- application.send_notification ("installed", notification);
199- }
200-
201 installed_packages.add_all (change_information.changes);
202 change_information.clear ();
203- installed = true;
204+
205+ if (exit_status == Pk.Exit.SUCCESS) {
206+ state = State.INSTALLED;
207+
208+ if ((window.get_state () & Gdk.WindowState.FOCUSED) == 0) {
209+ var notification = new Notification (_("Application installed"));
210+ notification.set_body (_("%s has been successfully installed").printf (get_name ()));
211+ notification.set_icon (new ThemedIcon ("system-software-install"));
212+ notification.set_default_action ("app.open-application");
213+
214+ application.send_notification ("installed", notification);
215+ }
216+ } else {
217+ state = previous_state;
218+ }
219+
220 changing = false;
221 } catch (Error e) {
222 change_information.reset ();
223 changing = false;
224+ state = previous_state;
225 throw e;
226 }
227 }
228@@ -99,16 +135,25 @@
229 public async void uninstall () throws GLib.Error {
230 action_cancellable.reset ();
231 changing = true;
232- changed ();
233+
234+ var previous_state = state;
235+ state = State.REMOVING;
236 try {
237- yield AppCenterCore.Client.get_default ().remove_package (this, (progress, type) => {change_information.ProgressCallback (progress, type);}, action_cancellable);
238+ var exit_status = yield AppCenterCore.Client.get_default ().remove_package (this, (progress, type) => {change_information.ProgressCallback (progress, type);}, action_cancellable);
239 installed_packages.clear ();
240 change_information.clear ();
241- installed = false;
242+
243+ if (exit_status == Pk.Exit.SUCCESS) {
244+ state = State.NOT_INSTALLED;
245+ } else {
246+ state = previous_state;
247+ }
248+
249 changing = false;
250 } catch (Error e) {
251 change_information.reset ();
252 changing = false;
253+ state = previous_state;
254 throw e;
255 }
256 }
257
258=== modified file 'src/Views/AppInfoView.vala'
259--- src/Views/AppInfoView.vala 2016-07-01 16:48:32 +0000
260+++ src/Views/AppInfoView.vala 2016-07-08 20:54:59 +0000
261@@ -21,7 +21,7 @@
262 using AppCenterCore;
263
264 public class AppCenter.Views.AppInfoView : Gtk.Grid {
265- AppCenterCore.Package package;
266+ Package package;
267
268 Gtk.Image app_icon;
269 Gtk.Image app_screenshot;
270@@ -41,12 +41,15 @@
271 Gtk.Button cancel_button;
272 Gtk.Stack action_stack;
273
274- public AppInfoView (AppCenterCore.Package package) {
275+ bool is_os_updates = false;
276+
277+ public AppInfoView (Package package) {
278 this.package = package;
279 app_name.label = package.get_name ();
280 app_summary.label = package.get_summary ();
281 parse_description (package.component.get_description ());
282 app_icon.gicon = package.get_icon (128);
283+ is_os_updates = package.component.id == "xxx-os-updates";
284
285 if (package.component.get_extensions ().length > 0) {
286 extension_box = new Gtk.ListBox ();
287@@ -63,29 +66,15 @@
288 load_extensions.begin ();
289 }
290
291- if (package.update_available) {
292- action_button.label = _("Update");
293- } else if (package.installed) {
294- action_button.no_show_all = true;
295- action_button.hide ();
296- } else {
297- uninstall_button.no_show_all = true;
298- uninstall_button.hide ();
299- }
300-
301- if (package.component.id == "xxx-os-updates") {
302- uninstall_button.no_show_all = true;
303- uninstall_button.hide ();
304- }
305-
306- package.notify["installed"].connect (() => update_buttons ());
307- package.notify["update-available"].connect (() => update_buttons ());
308+ package.notify["state"].connect (update_state);
309
310 package.change_information.bind_property ("can-cancel", cancel_button, "sensitive", GLib.BindingFlags.SYNC_CREATE);
311- package.change_information.progress_changed.connect (() => update_progress ());
312- package.change_information.status_changed.connect (() => update_status ());
313+ package.change_information.progress_changed.connect (update_progress);
314+ package.change_information.status_changed.connect (update_progress_status);
315+
316+ update_progress_status ();
317 update_progress ();
318- update_status ();
319+ update_state ();
320 }
321
322 construct {
323@@ -234,7 +223,7 @@
324 }
325
326 public void load_more_content () {
327- new Thread<void*> ("content loading", () => {
328+ new Thread<void*> ("content-loading", () => {
329 string url = null;
330 uint max_size = 0U;
331 package.component.get_screenshots ().foreach ((screenshot) => {
332@@ -256,42 +245,53 @@
333 });
334 }
335
336- private void update_status () {
337- progress_bar.text = package.change_information.get_status ();
338- if (package.change_information.status == Pk.Status.FINISHED) {
339- action_stack.set_visible_child_name ("buttons");
340- } else {
341- action_stack.set_visible_child_name ("progress");
342- }
343+ private void update_progress_status () {
344+ progress_bar.text = package.change_information.get_status ();
345 }
346
347 private void update_progress () {
348- var progress = package.change_information.get_progress ();
349+ double progress = package.change_information.get_progress ();
350 if (progress < 1.0f) {
351- action_stack.set_visible_child_name ("progress");
352 progress_bar.fraction = progress;
353+ }
354+ }
355+
356+ private void update_state () {
357+ if (package.state != Package.State.NOT_INSTALLED && !is_os_updates) {
358+ uninstall_button.no_show_all = false;
359+ uninstall_button.show_all ();
360 } else {
361- action_stack.set_visible_child_name ("buttons");
362+ uninstall_button.no_show_all = true;
363+ uninstall_button.hide ();
364 }
365- }
366-
367- private void update_buttons () {
368- if (package.installed) {
369- if (package.update_available) {
370+
371+ switch (package.state) {
372+ case Package.State.NOT_INSTALLED:
373+ action_button.label = _("Install");
374+ action_button.no_show_all = false;
375+ action_button.show_all ();
376+
377+ action_stack.set_visible_child_name ("buttons");
378+ break;
379+ case Package.State.INSTALLED:
380+ action_button.no_show_all = true;
381+ action_button.hide ();
382+
383+ action_stack.set_visible_child_name ("buttons");
384+ break;
385+ case Package.State.UPDATE_AVAILABLE:
386 action_button.label = _("Update");
387 action_button.no_show_all = false;
388- action_button.show_all ();
389- } else {
390- action_button.no_show_all = true;
391- action_button.hide ();
392- uninstall_button.no_show_all = false;
393- uninstall_button.show_all ();
394- }
395- } else {
396- action_button.label = _("Install");
397- action_button.no_show_all = false;
398- action_button.show_all ();
399- }
400+ action_button.show_all ();
401+
402+ action_stack.set_visible_child_name ("buttons");
403+ break;
404+ case Package.State.INSTALLING:
405+ case Package.State.UPDATING:
406+ case Package.State.REMOVING:
407+ action_stack.set_visible_child_name ("progress");
408+ break;
409+ }
410 }
411
412 private void action_cancelled () {
413@@ -302,38 +302,25 @@
414 try {
415 if (package.update_available) {
416 yield package.update ();
417- action_button.no_show_all = true;
418- action_button.hide ();
419 } else {
420 yield package.install ();
421- action_button.no_show_all = true;
422- action_button.hide ();
423- if (package.component.id != "xxx-os-updates") {
424- uninstall_button.no_show_all = false;
425- uninstall_button.show_all ();
426- }
427-
428+
429 // Add this app to the Installed Apps View
430 MainWindow.installed_view.add_app.begin (package);
431 }
432 } catch (Error e) {
433 critical (e.message);
434- action_stack.set_visible_child_name ("buttons");
435 }
436 }
437
438 private async void uninstall_clicked () {
439 try {
440 yield package.uninstall ();
441- action_button.label = _("Install");
442- uninstall_button.no_show_all = true;
443- uninstall_button.hide ();
444
445 // Remove this app from the Installed Apps View
446 MainWindow.installed_view.remove_app.begin (package);
447 } catch (Error e) {
448 critical (e.message);
449- action_stack.set_visible_child_name ("buttons");
450 }
451 }
452
453@@ -382,7 +369,8 @@
454 }
455
456 private void parse_description (string? description) {
457- if (description != null)
458+ if (description != null) {
459 app_description.buffer.text = AppStream.description_markup_convert_simple (description);
460+ }
461 }
462 }
463
464=== modified file 'src/Views/AppListView.vala'
465--- src/Views/AppListView.vala 2016-06-26 23:28:28 +0000
466+++ src/Views/AppListView.vala 2016-07-08 20:54:59 +0000
467@@ -191,7 +191,7 @@
468 uint current_update_number = update_numbers;
469 list_box.get_children ().foreach ((child) => {
470 var package = ((Widgets.PackageRow) child).package;
471- if (package.update_available) {
472+ if (package != null && package.update_available) {
473 package.notify["changing"].connect (() => {
474 if (package.changing) {
475 current_update_number--;
476
477=== modified file 'src/Widgets/PackageRow.vala'
478--- src/Widgets/PackageRow.vala 2016-06-29 21:40:17 +0000
479+++ src/Widgets/PackageRow.vala 2016-07-08 20:54:59 +0000
480@@ -40,21 +40,15 @@
481 package_summary.ellipsize = Pango.EllipsizeMode.END;
482 image.gicon = package.get_icon ();
483
484- if (package.update_available) {
485- action_button.label = _("Update");
486- } else if (package.installed) {
487- action_stack.no_show_all = true;
488- action_stack.hide ();
489- }
490-
491- package.notify["installed"].connect (() => update_buttons ());
492- package.notify["update-available"].connect (() => update_buttons ());
493+ package.notify["state"].connect (update_state);
494
495 package.change_information.bind_property ("can-cancel", cancel_button, "sensitive", GLib.BindingFlags.SYNC_CREATE);
496- package.change_information.progress_changed.connect (() => update_progress ());
497- package.change_information.status_changed.connect (() => update_status ());
498+ package.change_information.progress_changed.connect (update_progress);
499+ package.change_information.status_changed.connect (update_progress_status);
500+
501+ update_progress_status ();
502 update_progress ();
503- update_status ();
504+ update_state ();
505 }
506
507 construct {
508@@ -115,52 +109,56 @@
509 add (grid);
510 }
511
512- private void update_status () {
513+ private void update_progress_status () {
514 progress_bar.text = package.change_information.get_status ();
515- if (package.change_information.status == Pk.Status.FINISHED) {
516- action_stack.set_visible_child_name ("buttons");
517- } else {
518- action_stack.set_visible_child_name ("progress");
519- action_stack.no_show_all = false;
520- action_stack.show_all ();
521- }
522 }
523
524 private void update_progress () {
525- var progress = package.change_information.get_progress ();
526+ double progress = package.change_information.get_progress ();
527 if (progress < 1.0f) {
528- action_stack.set_visible_child_name ("progress");
529 progress_bar.fraction = progress;
530- action_stack.no_show_all = false;
531- action_stack.show_all ();
532- } else {
533- action_stack.set_visible_child_name ("buttons");
534 }
535 }
536
537- private void update_buttons () {
538- if (package.installed) {
539- if (package.update_available) {
540+ private void update_state () {
541+ switch (package.state) {
542+ case Package.State.NOT_INSTALLED:
543+ action_button.label = _("Install");
544+ action_button.no_show_all = false;
545+ action_button.show_all ();
546+
547+ action_stack.no_show_all = false;
548+ action_stack.show_all ();
549+
550+ action_stack.set_visible_child_name ("buttons");
551+ break;
552+ case Package.State.INSTALLED:
553+ action_stack.no_show_all = true;
554+ action_stack.hide ();
555+
556+ action_stack.set_visible_child_name ("buttons");
557+ break;
558+ case Package.State.UPDATE_AVAILABLE:
559 action_button.label = _("Update");
560 action_button.no_show_all = false;
561 action_button.show_all ();
562
563 action_stack.no_show_all = false;
564 action_stack.show_all ();
565- } else {
566- action_stack.no_show_all = true;
567- action_stack.hide ();
568- }
569- } else {
570- action_button.label = _("Install");
571- action_button.no_show_all = false;
572- action_button.show_all ();
573-
574- action_stack.no_show_all = false;
575- action_stack.show_all ();
576- }
577-
578- changed ();
579+
580+ action_stack.set_visible_child_name ("buttons");
581+ break;
582+ case Package.State.INSTALLING:
583+ case Package.State.UPDATING:
584+ case Package.State.REMOVING:
585+ action_stack.no_show_all = false;
586+ action_stack.show_all ();
587+
588+ action_stack.set_visible_child_name ("progress");
589+ break;
590+ }
591+
592+ changed ();
593 }
594
595 private void action_cancelled () {
596@@ -173,12 +171,12 @@
597 yield package.update ();
598 } else {
599 yield package.install ();
600+
601+ // Add this app to the Installed Apps View
602+ MainWindow.installed_view.add_app.begin (package);
603 }
604- action_stack.no_show_all = true;
605- action_stack.hide ();
606 } catch (Error e) {
607 critical (e.message);
608- action_stack.set_visible_child_name ("buttons");
609 }
610 }
611 }

Subscribers

People subscribed via source and target branches