mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-03 16:41:26 +01:00
fix(gui): show remote names as text, not Pango markup
Rows, toasts and status page descriptions parse their text as markup by default. Shared item names, inviter addresses, device names, link URLs, paths, EXIF values and daemon errors went in unescaped, so a name with `&` showed as an empty row and other names were drawn as markup. Those rows and toasts now use plain text, and status page descriptions are escaped (B232).
This commit is contained in:
1 parent
519ba0591a
commit
ef0f046939
19 files changed
+89
-14
No files matched your search
@@ -1065,8 +1065,17 @@ pub(crate) fn set_sidebar_badge(ui: &Ui, page: &str, count: u64) {
|
||||
/// Show a transient toast. Non-blocking by design: an action's outcome is
|
||||
/// reported without stealing focus or forcing a click, so the user can keep
|
||||
/// working while a slow upload lands.
|
||||
///
|
||||
/// A toast's title is Pango markup unless told otherwise. Messages carry file
|
||||
/// names and daemon errors, and one with a `&` or `<` in it showed as an empty
|
||||
/// toast, so every toast here is plain text.
|
||||
fn toast(ui: &Rc<Ui>, message: &str) {
|
||||
ui.toasts.add_toast(adw::Toast::new(message));
|
||||
ui.toasts.add_toast(
|
||||
adw::Toast::builder()
|
||||
.title(message)
|
||||
.use_markup(false)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Show a toast that offers one follow-up action — an Undo, or a way to the page
|
||||
@@ -1077,6 +1086,7 @@ fn toast(ui: &Rc<Ui>, message: &str) {
|
||||
fn toast_action(ui: &Rc<Ui>, message: &str, label: &str, action: impl Fn(&Rc<Ui>) + 'static) {
|
||||
let toast = adw::Toast::builder()
|
||||
.title(message)
|
||||
.use_markup(false)
|
||||
.button_label(label)
|
||||
.timeout(8)
|
||||
.build();
|
||||
@@ -1099,7 +1109,11 @@ fn toast_error(ui: &Rc<Ui>, what: &str, detail: &str) {
|
||||
gettext_f("{what}: {detail}", &[("what", what), ("detail", detail)])
|
||||
};
|
||||
tracing::warn!("{message}");
|
||||
let toast = adw::Toast::builder().title(&message).timeout(6).build();
|
||||
let toast = adw::Toast::builder()
|
||||
.title(&message)
|
||||
.use_markup(false)
|
||||
.timeout(6)
|
||||
.build();
|
||||
ui.toasts.add_toast(toast);
|
||||
}
|
||||
|
||||
|
||||
@@ -378,7 +378,9 @@ pub(crate) fn activity_status(
|
||||
) {
|
||||
ui.activity.status.set_icon_name(Some(icon));
|
||||
ui.activity.status.set_title(title);
|
||||
ui.activity.status.set_description(Some(description));
|
||||
ui.activity
|
||||
.status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.activity.retry.set_visible(retry);
|
||||
ui.activity.content.set_visible_child_name("status");
|
||||
}
|
||||
|
||||
@@ -645,7 +645,9 @@ pub(crate) fn close_album(ui: &Rc<Ui>) {
|
||||
fn albums_status(ui: &Rc<Ui>, icon: &str, title: &str, description: &str) {
|
||||
ui.gallery.albums_status.set_icon_name(Some(icon));
|
||||
ui.gallery.albums_status.set_title(title);
|
||||
ui.gallery.albums_status.set_description(Some(description));
|
||||
ui.gallery
|
||||
.albums_status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.gallery.albums_stack.set_visible_child_name("status");
|
||||
}
|
||||
|
||||
|
||||
@@ -500,7 +500,9 @@ pub(crate) fn build_browser_page() -> (gtk4::Widget, BrowserWidgets) {
|
||||
pub(crate) fn browser_status(ui: &Rc<Ui>, icon: &str, title: &str, description: &str, retry: bool) {
|
||||
ui.browser.status.set_icon_name(Some(icon));
|
||||
ui.browser.status.set_title(title);
|
||||
ui.browser.status.set_description(Some(description));
|
||||
ui.browser
|
||||
.status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.browser.retry.set_visible(retry);
|
||||
// Only the empty-folder state offers a way to fill the folder; every other
|
||||
// status (loading, offline, error) turns them back off.
|
||||
|
||||
@@ -204,7 +204,9 @@ pub(crate) fn wire_devices(ui: &Rc<Ui>, widgets: &DevicesWidgets) {
|
||||
pub(crate) fn devices_status(ui: &Rc<Ui>, icon: &str, title: &str, description: &str, retry: bool) {
|
||||
ui.devices.status.set_icon_name(Some(icon));
|
||||
ui.devices.status.set_title(title);
|
||||
ui.devices.status.set_description(Some(description));
|
||||
ui.devices
|
||||
.status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.devices.retry.set_visible(retry);
|
||||
ui.devices.content.set_visible_child_name("status");
|
||||
}
|
||||
@@ -390,6 +392,7 @@ fn this_computer_row(
|
||||
let row = adw::ActionRow::builder()
|
||||
.title(me.map_or_else(|| gettext("This computer"), |d| d.name.clone()))
|
||||
.subtitle(this_computer_subtitle(folders))
|
||||
.use_markup(false)
|
||||
.activatable(true)
|
||||
.build();
|
||||
row.add_prefix(>k4::Image::from_icon_name("computer-symbolic"));
|
||||
@@ -426,6 +429,7 @@ fn other_computer_row(ui: &Rc<Ui>, dev: &DeviceInfo) -> adw::ActionRow {
|
||||
let row = adw::ActionRow::builder()
|
||||
.title(&dev.name)
|
||||
.subtitle(device_subtitle(dev))
|
||||
.use_markup(false)
|
||||
.activatable(true)
|
||||
.build();
|
||||
row.add_prefix(>k4::Image::from_icon_name("computer-symbolic"));
|
||||
@@ -763,7 +767,10 @@ fn show_restore_picker(
|
||||
.active(true)
|
||||
.valign(gtk4::Align::Center)
|
||||
.build();
|
||||
let row = adw::EntryRow::builder().title(&f.name).build();
|
||||
let row = adw::EntryRow::builder()
|
||||
.title(&f.name)
|
||||
.use_markup(false)
|
||||
.build();
|
||||
row.set_text(&f.local_path);
|
||||
row.add_prefix(&check);
|
||||
group.add(&row);
|
||||
|
||||
@@ -209,7 +209,8 @@ fn ask(view: &Rc<FinderView>, finder: Finder, generation: u32) {
|
||||
Ok(Ok(Response::Error { message, .. })) => {
|
||||
view.status.set_icon_name(Some("dialog-warning-symbolic"));
|
||||
view.status.set_title(&failed);
|
||||
view.status.set_description(Some(&message));
|
||||
view.status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(&message)));
|
||||
view.progress.set_visible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1145,7 +1145,9 @@ pub(crate) fn locations_status(
|
||||
) {
|
||||
ui.locations.status.set_icon_name(Some(icon));
|
||||
ui.locations.status.set_title(title);
|
||||
ui.locations.status.set_description(Some(description));
|
||||
ui.locations
|
||||
.status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.locations.retry.set_visible(retry);
|
||||
ui.locations.content.set_visible_child_name("status");
|
||||
}
|
||||
|
||||
@@ -481,6 +481,7 @@ pub(crate) fn show_info(viewer: &Rc<Viewer>, path: &str, info: ExifInfo) {
|
||||
let row = adw::ActionRow::builder()
|
||||
.title(label.as_str())
|
||||
.subtitle(value)
|
||||
.use_markup(false)
|
||||
.subtitle_selectable(true)
|
||||
.build();
|
||||
row.add_css_class("property");
|
||||
|
||||
@@ -3459,7 +3459,9 @@ pub(crate) fn load_gallery(ui: &Rc<Ui>, append: bool) {
|
||||
pub(crate) fn gallery_status(ui: &Rc<Ui>, icon: &str, title: &str, description: &str, retry: bool) {
|
||||
ui.gallery.status.set_icon_name(Some(icon));
|
||||
ui.gallery.status.set_title(title);
|
||||
ui.gallery.status.set_description(Some(description));
|
||||
ui.gallery
|
||||
.status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.gallery.retry.set_visible(retry);
|
||||
// Only the empty timeline offers a way to fill it; every other status turns
|
||||
// those buttons back off.
|
||||
|
||||
@@ -448,7 +448,9 @@ pub(crate) fn close_place(ui: &Rc<Ui>) {
|
||||
fn places_status(ui: &Rc<Ui>, icon: &str, title: &str, description: &str) {
|
||||
ui.gallery.places_status.set_icon_name(Some(icon));
|
||||
ui.gallery.places_status.set_title(title);
|
||||
ui.gallery.places_status.set_description(Some(description));
|
||||
ui.gallery
|
||||
.places_status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.gallery.places_stack.set_visible_child_name("status");
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +311,9 @@ pub(crate) fn wire_shared(ui: &Rc<Ui>, widgets: &SharedWidgets) {
|
||||
pub(crate) fn shared_status(ui: &Rc<Ui>, icon: &str, title: &str, description: &str, retry: bool) {
|
||||
ui.shared.status.set_icon_name(Some(icon));
|
||||
ui.shared.status.set_title(title);
|
||||
ui.shared.status.set_description(Some(description));
|
||||
ui.shared
|
||||
.status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.shared.retry.set_visible(retry);
|
||||
ui.shared.content.set_visible_child_name("status");
|
||||
}
|
||||
@@ -818,6 +820,7 @@ fn invitation_row(inv: &InvitationInfo) -> adw::ActionRow {
|
||||
.title(&item)
|
||||
// Translators: {email} is the address of the person who sent the invitation.
|
||||
.subtitle(gettext_f("From {email}", &[("email", &inv.inviter_email)]))
|
||||
.use_markup(false)
|
||||
.build();
|
||||
row.add_prefix(>k4::Image::from_icon_name(if inv.is_dir {
|
||||
"folder-symbolic"
|
||||
@@ -862,6 +865,7 @@ fn repaint_links(ui: &Rc<Ui>, bookmarks: &[BookmarkInfo]) {
|
||||
let row = adw::ActionRow::builder()
|
||||
.title(&title)
|
||||
.subtitle(&bm.url)
|
||||
.use_markup(false)
|
||||
.subtitle_lines(1)
|
||||
.activatable(true)
|
||||
.tooltip_text(gettext("Open in browser"))
|
||||
|
||||
@@ -329,7 +329,9 @@ pub(crate) fn shared_by_me_status(
|
||||
) {
|
||||
ui.shared_by_me.status.set_icon_name(Some(icon));
|
||||
ui.shared_by_me.status.set_title(title);
|
||||
ui.shared_by_me.status.set_description(Some(description));
|
||||
ui.shared_by_me
|
||||
.status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.shared_by_me.retry.set_visible(retry);
|
||||
ui.shared_by_me.content.set_visible_child_name("status");
|
||||
ui.shared_by_me.subtitle.set_subtitle("");
|
||||
|
||||
@@ -1566,6 +1566,7 @@ pub(crate) fn repaint_pins(ui: &Rc<Ui>, pins: &[pdfs_core::cache::Pin], mounted:
|
||||
let row = adw::ActionRow::builder()
|
||||
.title(&name)
|
||||
.subtitle(&pin.path)
|
||||
.use_markup(false)
|
||||
.build();
|
||||
let icon = gtk4::Image::from_icon_name("pdfs-offline-symbolic");
|
||||
row.add_prefix(&icon);
|
||||
|
||||
@@ -510,6 +510,7 @@ pub(crate) fn repaint_archives(ui: &Rc<Ui>) {
|
||||
.unwrap_or_else(|| path.display().to_string()),
|
||||
)
|
||||
.subtitle(human_bytes(size))
|
||||
.use_markup(false)
|
||||
.build();
|
||||
let remove = gtk4::Button::builder()
|
||||
.icon_name("edit-delete-symbolic")
|
||||
|
||||
@@ -330,7 +330,9 @@ pub(crate) fn trash_unreachable(ui: &Rc<Ui>) {
|
||||
pub(crate) fn trash_status(ui: &Rc<Ui>, icon: &str, title: &str, description: &str, retry: bool) {
|
||||
ui.trash.status.set_icon_name(Some(icon));
|
||||
ui.trash.status.set_title(title);
|
||||
ui.trash.status.set_description(Some(description));
|
||||
ui.trash
|
||||
.status
|
||||
.set_description(Some(>k4::glib::markup_escape_text(description)));
|
||||
ui.trash.retry.set_visible(retry);
|
||||
ui.trash.content.set_visible_child_name("status");
|
||||
ui.trash.subtitle.set_subtitle("");
|
||||
|
||||
@@ -98,6 +98,8 @@ pub(crate) fn build_details_pane() -> (gtk4::Widget, DetailsWidgets) {
|
||||
.title(gettext("Location"))
|
||||
.subtitle("—")
|
||||
.subtitle_lines(3)
|
||||
// A folder path, which may hold `&` or `<`.
|
||||
.use_markup(false)
|
||||
.build();
|
||||
path_row.add_css_class("property");
|
||||
props.add(&size_row);
|
||||
|
||||
@@ -491,6 +491,7 @@ pub(crate) fn repaint_share_people(state: &Rc<ShareDialog>, entries: &[ShareEntr
|
||||
let row = adw::ActionRow::builder()
|
||||
.title(&entry.email)
|
||||
.subtitle(&subtitle)
|
||||
.use_markup(false)
|
||||
.build();
|
||||
row.add_prefix(&adw::Avatar::new(32, Some(&entry.email), true));
|
||||
|
||||
@@ -605,6 +606,7 @@ pub(crate) fn repaint_share_link(state: &Rc<ShareDialog>, link: Option<&PublicLi
|
||||
url.clone()
|
||||
})
|
||||
.subtitle(&subtitle)
|
||||
.use_markup(false)
|
||||
.build();
|
||||
row.add_css_class("property");
|
||||
|
||||
|
||||
@@ -219,6 +219,7 @@ fn repaint_versions(state: &Rc<VersionsDialog>, items: &[RevisionInfo]) {
|
||||
let row = adw::ActionRow::builder()
|
||||
.title(title)
|
||||
.subtitle(subtitle)
|
||||
.use_markup(false)
|
||||
.build();
|
||||
|
||||
let save = gtk4::Button::builder()
|
||||
|
||||
Reference in new issue
Block a user