improv(app): use about widget

This commit is contained in:
Vukašin Vojinović 2025-09-03 23:48:19 +02:00 committed by Jeremy Soller
parent f95869a631
commit 4d642ee3fa
4 changed files with 62 additions and 101 deletions

View file

@ -6,9 +6,6 @@ edition = "2024"
license = "GPL-3.0-only"
rust-version = "1.85"
[build-dependencies]
vergen = { version = "8", features = ["git", "gitcl"] }
[dependencies]
anyhow = "1"
chrono = { version = "0.4", features = ["unstable-locales"] }
@ -102,7 +99,12 @@ default = [
"xz2",
]
dbus-config = ["libcosmic/dbus-config"]
desktop = ["libcosmic/desktop", "dep:cosmic-mime-apps", "dep:xdg"]
desktop = [
"libcosmic/desktop",
"libcosmic/about",
"dep:cosmic-mime-apps",
"dep:xdg",
]
desktop-applet = []
gvfs = ["dep:gio", "dep:glib"]
io-uring = ["compio/io-uring", "dep:io-uring"]

View file

@ -1,17 +0,0 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Rebuild if i18n files change
println!("cargo:rerun-if-changed=i18n");
// Emit version information (if not cached by just vendor)
let mut vergen = vergen::EmitBuilder::builder();
println!("cargo:rerun-if-env-changed=VERGEN_GIT_COMMIT_DATE");
if std::env::var_os("VERGEN_GIT_COMMIT_DATE").is_none() {
vergen.git_commit_date();
}
println!("cargo:rerun-if-env-changed=VERGEN_GIT_SHA");
if std::env::var_os("VERGEN_GIT_SHA").is_none() {
vergen.git_sha(false);
}
vergen.fail_on_error().emit()?;
Ok(())
}

View file

@ -30,11 +30,11 @@ size = Size
# Progress footer
details = Details
dismiss = Dismiss message
operations-running = {$running} {$running ->
operations-running = {$running} {$running ->
[one] operation
*[other] operations
*[other] operations
} running ({$percent}%)...
operations-running-finished = {$running} {$running ->
operations-running-finished = {$running} {$running ->
[one] operation
*[other] operations
} running ({$percent}%), {$finished} finished...
@ -142,7 +142,7 @@ favorite-path-error = Error opening directory
favorite-path-error-description =
Unable to open "{$path}".
It may not exist or you don't have permission to open it.
Would you like to remove it from the sidebar?
remove = Remove
keep = Keep
@ -150,7 +150,8 @@ keep = Keep
# Context Pages
## About
git-description = Git commit {$hash} on {$date}
repository = Repository
support = Support
## Add Network Drive
add-network-drive = Add network drive

View file

@ -34,8 +34,9 @@ use cosmic::{
style, surface, theme,
widget::{
self,
about::About,
dnd_destination::DragId,
horizontal_space,
horizontal_space, icon,
menu::{action::MenuAction, key_bind::KeyBind},
segmented_button::{self, Entity},
vertical_space,
@ -634,6 +635,7 @@ impl PartialEq for WatcherWrapper {
// The [`App`] stores application-specific state.
pub struct App {
core: Core,
about: About,
nav_bar_context_id: segmented_button::Entity,
nav_model: segmented_button::SingleSelectModel,
tab_model: segmented_button::Model<segmented_button::SingleSelect>,
@ -1432,7 +1434,7 @@ impl App {
nav_model = nav_model.insert(|b| {
b.text(fl!("recents"))
.icon(widget::icon::from_name("document-open-recent-symbolic"))
.icon(icon::from_name("document-open-recent-symbolic"))
.data(Location::Recents)
});
@ -1448,12 +1450,10 @@ impl App {
nav_model = nav_model.insert(move |b| {
b.text(name.clone())
.icon(
widget::icon::icon(if path.is_dir() {
icon::icon(if path.is_dir() {
tab::folder_icon_symbolic(&path, 16)
} else {
widget::icon::from_name("text-x-generic-symbolic")
.size(16)
.handle()
icon::from_name("text-x-generic-symbolic").size(16).handle()
})
.size(16),
)
@ -1470,7 +1470,7 @@ impl App {
nav_model = nav_model.insert(|b| {
b.text(fl!("trash"))
.icon(widget::icon::icon(tab::trash_icon_symbolic(16)))
.icon(icon::icon(tab::trash_icon_symbolic(16)))
.data(Location::Trash)
.divider_above()
});
@ -1478,8 +1478,8 @@ impl App {
if !MOUNTERS.is_empty() {
nav_model = nav_model.insert(|b| {
b.text(fl!("networks"))
.icon(widget::icon::icon(
widget::icon::from_name("network-workgroup-symbolic")
.icon(icon::icon(
icon::from_name("network-workgroup-symbolic")
.size(16)
.handle(),
))
@ -1512,7 +1512,7 @@ impl App {
b = b.data(Location::Network(uri, item.name(), None));
}
if let Some(icon) = item.icon(true) {
b = b.icon(widget::icon::icon(icon).size(16));
b = b.icon(icon::icon(icon).size(16));
}
if item.is_mounted() {
b = b.closable();
@ -1618,38 +1618,6 @@ impl App {
Task::none()
}
fn about(&self) -> Element<Message> {
let cosmic_theme::Spacing { space_xxs, .. } = theme::active().cosmic().spacing;
let repository = "https://github.com/pop-os/cosmic-files";
let hash = env!("VERGEN_GIT_SHA");
let short_hash: String = hash.chars().take(7).collect();
let date = env!("VERGEN_GIT_COMMIT_DATE");
widget::column::with_children(vec![
widget::svg(widget::svg::Handle::from_memory(
&include_bytes!(
"../res/icons/hicolor/128x128/apps/com.system76.CosmicFiles.svg"
)[..],
))
.into(),
widget::text::title3(fl!("cosmic-files")).into(),
widget::button::link(repository)
.on_press(Message::LaunchUrl(repository.to_string()))
.padding(0)
.into(),
widget::button::link(fl!(
"git-description",
hash = short_hash.as_str(),
date = date
))
.on_press(Message::LaunchUrl(format!("{}/commits/{}", repository, hash)))
.padding(0)
.into(),
])
.align_x(Alignment::Center)
.spacing(space_xxs)
.into()
}
fn network_drive(&self) -> Element<Message> {
let cosmic_theme::Spacing {
space_xxs, space_m, ..
@ -1782,7 +1750,7 @@ impl App {
.into(),
if controller.is_paused() {
widget::tooltip(
widget::button::icon(widget::icon::from_name(
widget::button::icon(icon::from_name(
"media-playback-start-symbolic",
))
.on_press(Message::PendingPause(*id, false))
@ -1793,7 +1761,7 @@ impl App {
.into()
} else {
widget::tooltip(
widget::button::icon(widget::icon::from_name(
widget::button::icon(icon::from_name(
"media-playback-pause-symbolic",
))
.on_press(Message::PendingPause(*id, true))
@ -1804,7 +1772,7 @@ impl App {
.into()
},
widget::tooltip(
widget::button::icon(widget::icon::from_name("window-close-symbolic"))
widget::button::icon(icon::from_name("window-close-symbolic"))
.on_press(Message::PendingCancel(*id))
.padding(8),
widget::text::body(fl!("cancel")),
@ -2124,8 +2092,24 @@ impl Application for App {
})
});
let about = About::default()
.name(fl!("cosmic-files"))
.icon(icon::from_name(Self::APP_ID))
.version(env!("CARGO_PKG_VERSION"))
.author("System76")
.license("GPL-3.0-only")
.developers([("Jeremy Soller", "jeremy@system76.com")])
.links([
(fl!("repository"), "https://github.com/pop-os/cosmic-files"),
(
fl!("support"),
"https://github.com/pop-os/cosmic-files/issues",
),
]);
let mut app = App {
core,
about,
nav_bar_context_id: segmented_button::Entity::null(),
nav_model: segmented_button::ModelBuilder::default().build(),
tab_model: segmented_button::ModelBuilder::default().build(),
@ -2235,11 +2219,7 @@ impl Application for App {
cosmic::Action::App(Message::NavMenuAction(NavMenuAction::OpenInNewTab(entity)))
})
.context_menu(self.nav_context_menu(self.nav_bar_context_id))
.close_icon(
widget::icon::from_name("media-eject-symbolic")
.size(16)
.icon(),
)
.close_icon(icon::from_name("media-eject-symbolic").size(16).icon())
.into_container();
if !self.core.is_condensed() {
@ -3606,7 +3586,7 @@ impl Application for App {
});
if let Some(entity) = maybe_entity {
self.nav_model
.icon_set(entity, widget::icon::icon(tab::trash_icon_symbolic(16)));
.icon_set(entity, icon::icon(tab::trash_icon_symbolic(16)));
}
return Task::batch([self.rescan_trash(), self.update_desktop()]);
@ -4721,8 +4701,9 @@ impl Application for App {
}
Some(match &self.context_page {
ContextPage::About => context_drawer::context_drawer(
self.about(),
ContextPage::About => context_drawer::about(
&self.about,
Message::LaunchUrl,
Message::ToggleContextPage(ContextPage::About),
),
ContextPage::EditHistory => context_drawer::context_drawer(
@ -4932,7 +4913,7 @@ impl Application for App {
widget::dialog()
.title("Failed operation")
.body(format!("{:#?}\n{}", operation, err))
.icon(widget::icon::from_name("dialog-error").size(64))
.icon(icon::from_name("dialog-error").size(64))
//TODO: retry action
.primary_action(
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
@ -4941,7 +4922,7 @@ impl Application for App {
DialogPage::ExtractPassword { id, password } => {
widget::dialog()
.title(fl!("extract-password-required"))
.icon(widget::icon::from_name("dialog-error").size(64))
.icon(icon::from_name("dialog-error").size(64))
.control(widget::text_input("", password).password().on_input(
move |password| {
Message::DialogUpdate(DialogPage::ExtractPassword { id: *id, password })
@ -4962,7 +4943,7 @@ impl Application for App {
} => widget::dialog()
.title(fl!("mount-error"))
.body(error)
.icon(widget::icon::from_name("dialog-error").size(64))
.icon(icon::from_name("dialog-error").size(64))
.primary_action(
widget::button::standard(fl!("try-again")).on_press(Message::DialogComplete),
)
@ -5105,7 +5086,7 @@ impl Application for App {
} => widget::dialog()
.title(fl!("network-drive-error"))
.body(error)
.icon(widget::icon::from_name("dialog-error").size(64))
.icon(icon::from_name("dialog-error").size(64))
.primary_action(
widget::button::standard(fl!("try-again")).on_press(Message::DialogComplete),
)
@ -5216,7 +5197,7 @@ impl Application for App {
widget::mouse_area(
widget::button::custom(
widget::row::with_children(vec![
widget::icon(app.icon.clone()).size(32).into(),
icon(app.icon.clone()).size(32).into(),
if app.is_default && !displayed_default {
displayed_default = true;
widget::text::body(fl!(
@ -5229,9 +5210,7 @@ impl Application for App {
},
widget::horizontal_space().into(),
if *selected == i {
widget::icon::from_name("checkbox-checked-symbolic")
.size(16)
.into()
icon::from_name("checkbox-checked-symbolic").size(16).into()
} else {
widget::Space::with_width(Length::Fixed(16.0)).into()
},
@ -5473,7 +5452,7 @@ impl Application for App {
"favorite-path-error-description",
path = path.as_os_str().to_str()
))
.icon(widget::icon::from_name("dialog-error").size(64))
.icon(icon::from_name("dialog-error").size(64))
.primary_action(
widget::button::destructive(fl!("remove")).on_press(Message::DialogComplete),
)
@ -5547,29 +5526,25 @@ impl Application for App {
progress_bar.into(),
if all_paused {
widget::tooltip(
widget::button::icon(widget::icon::from_name(
"media-playback-start-symbolic",
))
.on_press(Message::PendingPauseAll(false))
.padding(8),
widget::button::icon(icon::from_name("media-playback-start-symbolic"))
.on_press(Message::PendingPauseAll(false))
.padding(8),
widget::text::body(fl!("resume")),
widget::tooltip::Position::Top,
)
.into()
} else {
widget::tooltip(
widget::button::icon(widget::icon::from_name(
"media-playback-pause-symbolic",
))
.on_press(Message::PendingPauseAll(true))
.padding(8),
widget::button::icon(icon::from_name("media-playback-pause-symbolic"))
.on_press(Message::PendingPauseAll(true))
.padding(8),
widget::text::body(fl!("pause")),
widget::tooltip::Position::Top,
)
.into()
},
widget::tooltip(
widget::button::icon(widget::icon::from_name("window-close-symbolic"))
widget::button::icon(icon::from_name("window-close-symbolic"))
.on_press(Message::PendingCancelAll)
.padding(8),
widget::text::body(fl!("cancel")),
@ -5618,7 +5593,7 @@ impl Application for App {
if self.core.is_condensed() {
elements.push(
//TODO: selected state is not appearing different
widget::button::icon(widget::icon::from_name("system-search-symbolic"))
widget::button::icon(icon::from_name("system-search-symbolic"))
.on_press(Message::SearchClear)
.padding(8)
.selected(true)
@ -5636,7 +5611,7 @@ impl Application for App {
}
} else {
elements.push(
widget::button::icon(widget::icon::from_name("system-search-symbolic"))
widget::button::icon(icon::from_name("system-search-symbolic"))
.on_press(Message::SearchActivate)
.padding(8)
.into(),