Skip to content
11 changes: 11 additions & 0 deletions changelogs/24.04
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
* Includes COSMIC desktop environment.

* Pop!_OS 24.04 includes the COSMIC desktop environment. COSMIC offers better performance, productivity, and in-depth personalization to empower a wide variety of use cases.

* When you upgrade:
** GNOME desktop will be replaced by the new COSMIC desktop.
** New system applications will be installed: COSMIC Files, COSMIC Settings, COSMIC Store, COSMIC Terminal, COSMIC Text Editor.
** Applications pinned tot he dock will need to be pinned again.
** PPAs will be removed for increased upgrade reliability.
** Applications installed from PPAs or local DEB files will need to be reinstalled.
** COSMIC offers all new user settings and customizations.
1 change: 1 addition & 0 deletions daemon/src/changelogs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::cmp::Ordering;

pub const CHANGELOGS: &[(&str, &str)] = &[
("24.04", include_str!("../../changelogs/24.04")),
("22.04", include_str!("../../changelogs/22.04")),
("21.10", include_str!("../../changelogs/21.10")),
("21.04", include_str!("../../changelogs/21.04")),
Expand Down
8 changes: 4 additions & 4 deletions daemon/src/release/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ const HIRSUTE: &str = "21.04";
const IMPISH: &str = "21.10";
const JAMMY: &str = "22.04";
const NOBLE: &str = "24.04";
const UNKNOWN: &str = "26.04";
const RESOLUTE: &str = "26.04";

pub fn release_str(major: u8, minor: u8) -> &'static str {
match (major, minor) {
Expand All @@ -112,7 +112,7 @@ pub fn release_str(major: u8, minor: u8) -> &'static str {
(21, 10) => IMPISH,
(22, 4) => JAMMY,
(24, 4) => NOBLE,
(26, 4) => UNKNOWN,
(26, 4) => RESOLUTE,
_ => panic!("this version of pop-upgrade is not supported on this release"),
}
}
Expand Down Expand Up @@ -145,8 +145,8 @@ async fn next_<Check: Fn(String) -> Status, Status: Future<Output = BuildStatus>
(20, 10) => available(false, GROOVY, HIRSUTE).await,
(21, 4) => available(false, HIRSUTE, IMPISH).await,
(21, 10) => available(false, IMPISH, JAMMY).await,
(22, 4) => development_enabled(true, JAMMY, NOBLE).await,
(24, 4) => blocked(true, NOBLE, UNKNOWN).await,
(22, 4) => available(true, JAMMY, NOBLE).await,
(24, 4) => blocked(true, NOBLE, RESOLUTE).await,
_ => panic!("this version of pop-upgrade is not supported on this release"),
}
}
5 changes: 5 additions & 0 deletions daemon/src/ubuntu_version/codename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub enum Codename {
Impish,
Jammy,
Noble,
Resolute,
}

impl Codename {
Expand Down Expand Up @@ -49,6 +50,7 @@ impl Codename {
Codename::Impish => (2021, 10, 14),
Codename::Jammy => (2022, 4, 21),
Codename::Noble => (2024, 4, 13),
Codename::Resolute => (2026, 4, 23),
}
}

Expand All @@ -66,6 +68,7 @@ impl Codename {
Codename::Impish => 1_634_191_200,
Codename::Jammy => 1_650_492_000,
Codename::Noble => 1_712_959_200,
Codename::Resolute => 1_776_895_200
}
}
}
Expand All @@ -89,6 +92,7 @@ impl FromStr for Codename {
"impish" => Codename::Impish,
"jammy" => Codename::Jammy,
"noble" => Codename::Noble,
"resolute" => Codename::Resolute,
_ => return Err(CodenameParseError::NotFound),
};

Expand All @@ -109,6 +113,7 @@ impl From<Codename> for &'static str {
Codename::Impish => "impish",
Codename::Jammy => "jammy",
Codename::Noble => "noble",
Codename::Resolute => "resolute",
}
}
}
1 change: 1 addition & 0 deletions daemon/src/ubuntu_version/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ impl From<Codename> for Version {
Codename::Impish => (21, 10),
Codename::Jammy => (22, 4),
Codename::Noble => (24, 4),
Codename::Resolute => (26, 4),
};

Version { major, minor, patch: 0 }
Expand Down
110 changes: 44 additions & 66 deletions gtk/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@ use crate::{
RECOVERY_PARTITION, REFRESH_OS,
};

use chrono::{TimeZone, Utc};
use gtk::prelude::*;

use pop_upgrade::{
daemon::{DaemonStatus, DISMISSED},
recovery::RecoveryEvent,
release::{
eol::{EolDate, EolStatus},
UpgradeEvent,
},
};
Expand Down Expand Up @@ -185,7 +183,20 @@ pub async fn on_event(widgets: &mut EventWidgets, state: &mut State, event: UiEv
UiEvent::Upgrade(event) => match event {
OsUpgradeEvent::Cancelled => cancelled_upgrade(state, widgets),

OsUpgradeEvent::Dialog => release_upgrade_dialog(state, widgets),
OsUpgradeEvent::Dialog => {
let dialog = UpgradeDialog::new(&state.upgrading_from, &state.upgrading_to, false);

let answer = dialog.run();
dialog.close();
if gtk::ResponseType::Accept == answer {
let _ = state.sender.send(BackgroundEvent::Finalize);
} else {
// Send upgrading event to prevent closing
(state.callback_event.borrow())(Event::Upgrading);
widgets.upgrade.options[0].label(&fl!("upgrade-canceling"));
let _ = state.sender.send(BackgroundEvent::Reset);
}
}

OsUpgradeEvent::Dismissed(dismissed) => {
info!("{} release", if dismissed { "dismissed" } else { "un-dismissed" });
Expand All @@ -207,7 +218,7 @@ pub async fn on_event(widgets: &mut EventWidgets, state: &mut State, event: UiEv

OsUpgradeEvent::Notification => (state.callback_ready.borrow())(),

OsUpgradeEvent::Upgrade => upgrade_clicked(state, widgets),
OsUpgradeEvent::Upgrade => release_upgrade_dialog(state, widgets),
},

UiEvent::Updating => {
Expand Down Expand Up @@ -315,34 +326,11 @@ fn connect_refresh(state: &State, widgets: &EventWidgets) {

/// Programs the upgrade button, and optionally enables the dismissal widget.
fn connect_upgrade(state: &mut State, widgets: &EventWidgets, is_lts: bool, reboot_ready: bool) {
let notice = match EolDate::fetch() {
Ok(eol) => {
let (y, m, d) = eol.ymd;
match eol.status() {
EolStatus::Exceeded => Some(fl!(
"eol-exceeded",
current = fomat!((eol.version)),
next = fomat!((eol.version.next_release()))
)),
EolStatus::Imminent => Some(fl!(
"eol-imminent",
current = fomat!((eol.version)),
date = fomat!((Utc.ymd(y as i32, m, d).format("%B %-d, %Y")))
)),
EolStatus::Ok => None,
}
}
Err(why) => {
error!("{}: {}", fl!("eol-error"), why);
None
}
};

let notice = notice.as_deref();
let notice = fl!("upgrade-cosmic");

widgets.upgrade.options[0]
.label(&state.upgrade_label)
.sublabel(notice)
.sublabel(Some(notice.as_str()))
.show_button()
.button_signal({
if let Some(info) = state.upgrade_version.as_ref() {
Expand Down Expand Up @@ -381,7 +369,7 @@ fn download_action(sender: sync::Weak<flume::Sender<UiEvent>>) -> (String, Box<d
}
});

(fl!("button-download"), action)
(fl!("button-upgrade"), action)
}

/// Notify that OS release updates have been downloaded, and are ready to commence.
Expand Down Expand Up @@ -473,17 +461,32 @@ fn is_dismissed(next: &str) -> bool {

/// When the user selects to commence an upgrade, a dialog is shown to confirm.
fn release_upgrade_dialog(state: &mut State, widgets: &EventWidgets) {
let dialog = UpgradeDialog::new(&state.upgrading_from, &state.upgrading_to);

let answer = dialog.run();
dialog.close();
if gtk::ResponseType::Accept == answer {
let _ = state.sender.send(BackgroundEvent::Finalize);
} else {
// Send upgrading event to prevent closing
if let Some(info) = state.upgrade_version.clone() {
(state.callback_event.borrow())(Event::Upgrading);
widgets.upgrade.options[0].label(&fl!("upgrade-canceling"));
let _ = state.sender.send(BackgroundEvent::Reset);

widgets.upgrade.options[0].label(&fl!("upgrade-preparing")).show_progress();

widgets.recovery.options[RECOVERY_PARTITION].sensitive(false);
widgets.recovery.options[REFRESH_OS].sensitive(false);

if let Some(dismisser) = state.dismisser.take() {
unsafe {
dismisser.destroy();
}
}

let dialog = UpgradeDialog::new(&state.upgrading_from, &state.upgrading_to, true);

let answer = dialog.run();
dialog.close();
if gtk::ResponseType::Accept == answer {
let _ = state.sender.send(BackgroundEvent::DownloadUpgrade(info));
} else {
// Send upgrading event to prevent closing
(state.callback_event.borrow())(Event::Upgrading);
widgets.upgrade.options[0].label(&fl!("upgrade-canceling"));
let _ = state.sender.send(BackgroundEvent::Reset);
}
}
}

Expand Down Expand Up @@ -587,32 +590,7 @@ fn upgrade_action(sender: sync::Weak<flume::Sender<UiEvent>>) -> (String, Box<dy
}
});

(fl!("button-upgrade"), action)
}

/// Triggers on clicking the upgrade button
fn upgrade_clicked(state: &mut State, widgets: &EventWidgets) {
if state.upgrade_downloaded {
release_upgrade_dialog(state, widgets);
return;
}

if let Some(info) = state.upgrade_version.clone() {
(state.callback_event.borrow())(Event::Upgrading);

widgets.upgrade.options[0].label(&fl!("upgrade-preparing")).show_progress();

widgets.recovery.options[RECOVERY_PARTITION].sensitive(false);
widgets.recovery.options[REFRESH_OS].sensitive(false);

if let Some(dismisser) = state.dismisser.take() {
unsafe {
dismisser.destroy();
}
}

let _ = state.sender.send(BackgroundEvent::DownloadUpgrade(info));
}
(fl!("button-perform-upgrade"), action)
}

mod recovery {
Expand Down
89 changes: 48 additions & 41 deletions gtk/src/widgets/dialogs/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,58 @@ pub struct UpgradeDialog {
}

impl UpgradeDialog {
pub fn new(since: &str, version: &str) -> Self {
let title = gtk::Label::builder()
.label(&fomat!(
(fl!("upgrade-available", version = version)) " "
if battery::active() {
(fl!("battery-notice")) " "
}
(fl!("new-features-include"))
))
.use_markup(true)
.xalign(0.0)
.build();
let changelog_list = gtk::Box::new(gtk::Orientation::Vertical, 24);

let scroller = cascade! {
gtk::ScrolledWindow::new(None::<&gtk::Adjustment>, None::<&gtk::Adjustment>);
..set_hexpand(true);
..set_vexpand(true);
..add(&changelog_list);
};

let mut iter = changelogs::since(since);

match iter.next() {
Some((_version, changelog)) => {
add_changelog(&changelog_list, changelog);
for (version, changelog) in iter {
changelog_list.add(&gtk::Separator::new(gtk::Orientation::Horizontal));
add_version(&changelog_list, version);
add_changelog(&changelog_list, changelog);
}
}
None => {
add_changelog(&changelog_list, &fl!("error-no-changelog-found"));
}
}

pub fn new(since: &str, version: &str, start: bool) -> Self {
let dialog = DialogTemplate::new(
"distributor-logo",
&fl!("button-upgrade"),
&fl!("button-perform-upgrade"),
&fl!("upgrade-to"),
&if start {
fl!("button-upgrade")
} else {
fl!("button-perform-upgrade")
},
&gtk::STYLE_CLASS_DESTRUCTIVE_ACTION,
|content| {
content.add(&title);
content.add(&scroller);
if start {
let changelog_list = gtk::Box::new(gtk::Orientation::Vertical, 24);
let scroller = cascade! {
gtk::ScrolledWindow::new(None::<&gtk::Adjustment>, None::<&gtk::Adjustment>);
..set_hexpand(true);
..set_vexpand(true);
..add(&changelog_list);
};

let mut iter = changelogs::since(since);

match iter.next() {
Some((_version, changelog)) => {
add_changelog(&changelog_list, changelog);
for (version, changelog) in iter {
changelog_list.add(&gtk::Separator::new(gtk::Orientation::Horizontal));
add_version(&changelog_list, version);
add_changelog(&changelog_list, changelog);
}
}
None => {
add_changelog(&changelog_list, &fl!("error-no-changelog-found"));
}
}

content.add(&scroller);
} else {
let message = gtk::Label::builder()
.label(&fomat!(
(fl!("upgrade-available", version = version)) " "
if battery::active() {
(fl!("battery-notice")) " "
}
(fl!("upgrade-finalize"))
))
.use_markup(true)
.xalign(0.0)
.build();

content.add(&message);
}
},
);

Expand Down
10 changes: 6 additions & 4 deletions i18n/en/pop_upgrade_gtk.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ battery-notice = <b>Plug into power</b> before you begin.

button-cancel = Cancel
button-dismiss = Dismiss
button-download = Download
button-perform-refresh = Reboot & Refresh
button-perform-upgrade = Reboot & Upgrade
button-perform-refresh = Restart & Refresh
button-perform-upgrade = Restart & Install
button-refresh = Refresh
button-update = Update
button-upgrade = Upgrade
button-upgrade = Start Upgrade

checking-for-updates = Checking for updates ...

Expand Down Expand Up @@ -85,8 +84,11 @@ refresh-header = Refresh OS
release-current = You are running the most current {-os} version

upgrade-available = {-os} {$version} is available!
upgrade-cosmic = Includes COSMIC desktop environment
upgrade-canceling = Canceling upgrade
upgrade-downloading = {-os} is currently downloading
upgrade-finalize = The system will be upgraded to {-os} 24.04.
upgrade-from-to = Upgrade from {$current} to {$next} is available
upgrade-preparing = Preparing Upgrade
upgrade-ready = {-os} is ready to upgrade to {$version}
upgrade-to = Upgrade to {-os} 24.04