Skip to content
4 changes: 1 addition & 3 deletions src/Views/AppInfoView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -1220,9 +1220,7 @@ namespace AppCenter.Views {
private async void uninstall_clicked () {
package.uninstall.begin ((obj, res) => {
try {
if (package.uninstall.end (res)) {
MainWindow.installed_view.remove_app.begin (package);
}
package.uninstall.end (res);
} catch (Error e) {
// Disable error dialog for if user clicks cancel. Reason: Failed to obtain authentication
// Pk ErrorEnums are mapped to the error code at an offset of 0xFF (see packagekit-glib2/pk-client.h)
Expand Down
145 changes: 59 additions & 86 deletions src/Views/AppListUpdateView.vala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*-
* Copyright (c) 2014-2020 elementary, Inc. (https://elementary.io)
* Copyright 2014-2023 elementary, Inc. (https://elementary.io)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -29,12 +29,15 @@ namespace AppCenter.Views {
private Gtk.ListBox list_box;
private Gtk.Revealer header_revealer;
private Gtk.SizeGroup action_button_group;
private ListStore package_liststore;
private Widgets.SizeLabel size_label;
private bool updating_all_apps = false;
private Cancellable? refresh_cancellable = null;
private AsyncMutex refresh_mutex = new AsyncMutex ();

construct {
package_liststore = new ListStore (typeof (AppCenterCore.Package));

var css_provider = new Gtk.CssProvider ();
css_provider.load_from_resource ("io/elementary/appcenter/AppListUpdateView.css");

Expand Down Expand Up @@ -75,7 +78,7 @@ namespace AppCenter.Views {
hexpand = true,
vexpand = true
};
list_box.set_sort_func ((Gtk.ListBoxSortFunc) package_row_compare);
list_box.bind_model (package_liststore, create_row_from_package);
list_box.set_header_func ((Gtk.ListBoxUpdateHeaderFunc) row_update_header);
list_box.set_placeholder (loading_view);

Expand Down Expand Up @@ -130,6 +133,10 @@ namespace AppCenter.Views {
});
});

package_liststore.items_changed.connect (() => {
list_box.show_all ();
});

list_box.row_activated.connect ((row) => {
if (row is Widgets.PackageRow) {
show_app (((Widgets.PackageRow) row).get_package ());
Expand Down Expand Up @@ -172,21 +179,27 @@ namespace AppCenter.Views {
var installed_apps = yield client.get_installed_applications (refresh_cancellable);

if (!refresh_cancellable.is_cancelled ()) {
clear ();
package_liststore.remove_all ();

var os_updates = AppCenterCore.UpdateManager.get_default ().os_updates;
var os_updates_size = yield os_updates.get_download_size_including_deps ();
if (os_updates_size > 0) {
add_package (os_updates);
package_liststore.insert_sorted (os_updates, compare_package_func);
}

var runtime_updates = AppCenterCore.UpdateManager.get_default ().runtime_updates;
var runtime_updates_size = yield runtime_updates.get_download_size_including_deps ();
if (runtime_updates_size > 0) {
add_package (runtime_updates);
package_liststore.insert_sorted (runtime_updates, compare_package_func);
}

add_packages (installed_apps);
foreach (var package in installed_apps) {
var needs_update = package.state == AppCenterCore.Package.State.UPDATE_AVAILABLE;
// Only add row if this package needs an update or it's not a font or plugin
if (needs_update || (package.kind != AppStream.ComponentKind.ADDON && package.kind != AppStream.ComponentKind.FONT)) {
package_liststore.insert_sorted (package, compare_package_func);
}
}
}

yield client.get_prepared_applications (refresh_cancellable);
Expand All @@ -195,49 +208,28 @@ namespace AppCenter.Views {
refresh_mutex.unlock ();
}

public void add_packages (Gee.Collection<AppCenterCore.Package> packages) {
foreach (var package in packages) {
add_row_for_package (package);
}

list_box.invalidate_sort ();
}

public void add_package (AppCenterCore.Package package) {
add_row_for_package (package);
list_box.invalidate_sort ();
}

private void add_row_for_package (AppCenterCore.Package package) {
var needs_update = package.state == AppCenterCore.Package.State.UPDATE_AVAILABLE;

// Only add row if this package needs an update or it's not a font or plugin
if (needs_update || (package.kind != AppStream.ComponentKind.ADDON && package.kind != AppStream.ComponentKind.FONT)) {
var row = new Widgets.PackageRow.installed (package, action_button_group);
row.show_all ();

list_box.add (row);
}
private Gtk.Widget create_row_from_package (Object object) {
unowned var package = (AppCenterCore.Package) object;
return new Widgets.PackageRow.installed (package, action_button_group);
}

[CCode (instance_pos = -1)]
private int package_row_compare (Widgets.PackageRow row1, Widgets.PackageRow row2) {
var row1_package = row1.get_package ();
var row2_package = row2.get_package ();
private int compare_package_func (Object object1, Object object2) {
var package1 = (AppCenterCore.Package) object1;
var package2 = (AppCenterCore.Package) object2;

bool a_has_updates = false;
bool a_is_driver = false;
bool a_is_os = false;
bool a_is_runtime = false;
bool a_is_updating = false;
string a_package_name = "";
if (row1_package != null) {
a_has_updates = row1_package.update_available;
a_is_driver = row1_package.kind == AppStream.ComponentKind.DRIVER;
a_is_os = row1_package.is_os_updates;
a_is_runtime = row1_package.is_runtime_updates;
a_is_updating = row1_package.is_updating;
a_package_name = row1_package.get_name ();
if (package1 != null) {
a_has_updates = package1.update_available;
a_is_driver = package1.kind == AppStream.ComponentKind.DRIVER;
a_is_os = package1.is_os_updates;
a_is_runtime = package1.is_runtime_updates;
a_is_updating = package1.is_updating;
a_package_name = package1.get_name ();
}

bool b_has_updates = false;
Expand All @@ -246,13 +238,13 @@ namespace AppCenter.Views {
bool b_is_runtime = false;
bool b_is_updating = false;
string b_package_name = "";
if (row2_package != null) {
b_has_updates = row2_package.update_available;
b_is_driver = row2_package.kind == AppStream.ComponentKind.DRIVER;
b_is_os = row2_package.is_os_updates;
b_is_runtime = row2_package.is_runtime_updates;
b_is_updating = row2_package.is_updating;
b_package_name = row2_package.get_name ();
if (package2 != null) {
b_has_updates = package2.update_available;
b_is_driver = package2.kind == AppStream.ComponentKind.DRIVER;
b_is_os = package2.is_os_updates;
b_is_runtime = package2.is_runtime_updates;
b_is_updating = package2.is_updating;
b_package_name = package2.get_name ();
}

// The currently updating package is always top of the list
Expand Down Expand Up @@ -366,23 +358,25 @@ namespace AppCenter.Views {
foreach (unowned var child in list_box.get_children ()) {
if (child is Widgets.PackageRow) {
((Widgets.PackageRow) child).set_action_sensitive (false);
}
}

var package = ((Widgets.PackageRow) child).get_package ();
if (package.update_available && !package.should_pay) {
try {
yield package.update (false);
} catch (Error e) {
// If one package update was cancelled, drop out of the loop of updating the rest
if (e is GLib.IOError.CANCELLED) {
break;
} else {
var fail_dialog = new UpgradeFailDialog (package, e.message) {
modal = true,
transient_for = (Gtk.Window) get_toplevel ()
};
fail_dialog.present ();
break;
}
for (int i = 0; i < package_liststore.get_n_items (); i++) {
var package = (AppCenterCore.Package) package_liststore.get_item (i);
if (package.update_available && !package.should_pay) {
try {
yield package.update (false);
} catch (Error e) {
// If one package update was cancelled, drop out of the loop of updating the rest
if (e is GLib.IOError.CANCELLED) {
break;
} else {
var fail_dialog = new UpgradeFailDialog (package, e.message) {
modal = true,
transient_for = (Gtk.Window) get_toplevel ()
};
fail_dialog.present ();
break;
}
}
}
Expand All @@ -399,35 +393,14 @@ namespace AppCenter.Views {
var installed_apps = yield client.get_installed_applications ();
foreach (var app in installed_apps) {
if (app == package) {
add_package (app);
package_liststore.insert_sorted (package, compare_package_func);
break;
}
}
}

public async void remove_app (AppCenterCore.Package package) {
foreach (unowned var child in list_box.get_children ()) {
if (child is Widgets.PackageRow) {
unowned var row = (Widgets.PackageRow) child;

if (row.get_package () == package) {
row.destroy ();
break;
}
}
}

list_box.invalidate_sort ();
}

public void clear () {
foreach (unowned var child in list_box.get_children ()) {
if (child is Widgets.PackageRow) {
child.destroy ();
}
};

list_box.invalidate_sort ();
package_liststore.remove_all ();
}
}
}