From e6134bc0d1c00f6657efc8b3a6bd9f57a9635c47 Mon Sep 17 00:00:00 2001 From: TomZz Date: Wed, 17 Jun 2026 04:06:25 +0800 Subject: [PATCH] fix: sftp panel status bar layout bug, update localized strings and add Open Transfer History shortcut --- locales/en.yml | 5 ++++ locales/zh-CN.yml | 8 +++-- src/app/dialogs.rs | 53 +++++++++++++++++++++++++++++++++- src/app/keybinding_recorder.rs | 10 ++++++- src/app/mod.rs | 12 +++++++- src/app/startup.rs | 25 +++++++++++++++- src/app/ui.rs | 33 ++++++++++++++++----- src/main.rs | 4 +-- 8 files changed, 135 insertions(+), 15 deletions(-) diff --git a/locales/en.yml b/locales/en.yml index 080b32c..c343a76 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -136,6 +136,11 @@ transfers_limit: " (Max 100 records)" press_new_key: "Press new key..." settings_open_settings: "Open Settings" settings_open_session: "Open Session" +settings_open_transfers: "Open Transfer History" +files_downloading: "%{count} files downloading" +files_uploading: "%{count} files uploading" +panel_minimize: "Minimize Panel" +panel_expand: "Expand Panel" settings_new_ssh: "New SSH" settings_toggle_sidebar: "Toggle Sidebar" settings_toggle_sftp_zoom: "Toggle SFTP Zoom" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 03a378a..665e86d 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -23,7 +23,6 @@ system_path_warning: "警告:您即将删除系统关键路径!这可能会 delete_success: "成功删除 %{count} 个项" delete_failed: "删除失败: %{err}" deleting_paths: "正在删除 %{count} 个项..." -cancel: "取消" confirm: "确认" local_terminal: "本地终端" open_local_shell_tab: "打开一个新的本地终端页面" @@ -139,6 +138,11 @@ transfers_limit: " (最多保留 100 条)" press_new_key: "请按下新的快捷键..." settings_open_settings: "打开设置" settings_open_session: "打开会话" +settings_open_transfers: "打开传输历史" +files_downloading: "%{count} 个文件正在下载" +files_uploading: "%{count} 个文件正在上传" +panel_minimize: "折叠面板" +panel_expand: "展开面板" settings_new_ssh: "新建 SSH" settings_toggle_sidebar: "缩放侧边栏" settings_toggle_sftp_zoom: "缩放 SFTP 面板" @@ -151,4 +155,4 @@ settings_split_pane_right: "向右拆分面板" settings_split_pane_up: "向上拆分面板" settings_split_pane_down: "向下拆分面板" settings_close_pane: "关闭当前面板" -keybind_conflict: "\"%{key}\" 已被「%{action}」使用,请选择其他快捷键" +keybind_conflict: '"%{key}" 已被「%{action}」使用,请选择其他快捷键' diff --git a/src/app/dialogs.rs b/src/app/dialogs.rs index bd866ed..01c0b6a 100644 --- a/src/app/dialogs.rs +++ b/src/app/dialogs.rs @@ -21,6 +21,11 @@ use crate::{Ashell, session::config::AuthMethod, system::format_bytes}; impl Ashell { pub(crate) fn show_ssh_dialog(&mut self, window: &mut Window, cx: &mut Context) { + if self.active_dialog.is_some() { + return; + } + self.active_dialog = Some(crate::app::DialogKind::NewSsh); + let view = cx.entity(); let session_name_input = self.session_name_input.clone(); let host_input = self.host_input.clone(); @@ -37,6 +42,15 @@ impl Ashell { .title(t!("new_ssh_connection")) .w(px(520.)) .overlay_closable(true) + .on_close({ + let view = view.clone(); + move |_, _, cx| { + view.update(cx, |this, cx| { + this.active_dialog = None; + cx.notify(); + }); + } + }) .content({ let view = view.clone(); let session_name_input = session_name_input.clone(); @@ -173,6 +187,11 @@ impl Ashell { }); } pub(crate) fn show_selector_dialog(&mut self, window: &mut Window, cx: &mut Context) { + if self.active_dialog.is_some() { + return; + } + self.active_dialog = Some(crate::app::DialogKind::SessionSelector); + let view = cx.entity(); let selector_focus_handle = self.selector_focus_handle.clone(); let deferred_selector_focus_handle = selector_focus_handle.clone(); @@ -183,6 +202,15 @@ impl Ashell { dialog .title(t!("open_session").to_string()) .w(px(520.)) + .on_close({ + let view = view.clone(); + move |_, _, cx| { + view.update(cx, |this, cx| { + this.active_dialog = None; + cx.notify(); + }); + } + }) .on_ok({ let view = view.clone(); move |_, window, cx| { @@ -405,9 +433,26 @@ impl Ashell { }); } pub(crate) fn show_transfers_dialog(&mut self, window: &mut Window, cx: &mut Context) { + if self.active_dialog.is_some() { + return; + } + self.active_dialog = Some(crate::app::DialogKind::Transfers); + let view = cx.entity(); window.open_dialog(cx, move |dialog: Dialog, _window, _| { - dialog.w(px(600.)).close_button(false).content({ + dialog + .w(px(600.)) + .close_button(false) + .on_close({ + let view = view.clone(); + move |_, _, cx| { + view.update(cx, |this, cx| { + this.active_dialog = None; + cx.notify(); + }); + } + }) + .content({ let view = view.clone(); move |content, window, cx| { let can_clear = view.read(cx).transfers.iter().any(|t| { @@ -997,6 +1042,11 @@ impl Ashell { }); } pub(crate) fn show_settings_dialog(&mut self, window: &mut Window, cx: &mut Context) { + if self.active_dialog.is_some() { + return; + } + self.active_dialog = Some(crate::app::DialogKind::Settings); + let view = cx.entity(); // Unbind all workspace keys so they don't interfere with keybinding recording @@ -1013,6 +1063,7 @@ impl Ashell { move |_, _window, cx| { // Re-register all workspace keys when closing settings view.update(cx, |this, cx| { + this.active_dialog = None; this.keybinds_suspended = false; this.recording_action = None; this.keybind_error = None; diff --git a/src/app/keybinding_recorder.rs b/src/app/keybinding_recorder.rs index 664d462..c58cfe5 100644 --- a/src/app/keybinding_recorder.rs +++ b/src/app/keybinding_recorder.rs @@ -16,6 +16,7 @@ gpui::actions!( [ OpenSettings, OpenSession, + OpenTransfers, NewSsh, ToggleSidebar, ToggleSftpZoom, @@ -51,6 +52,11 @@ pub(crate) const WORKSPACE_ACTIONS: &[WorkspaceAction] = &[ label_key: "settings_open_session", default_suffix: "o", }, + WorkspaceAction { + id: "OpenTransfers", + label_key: "settings_open_transfers", + default_suffix: "t", + }, WorkspaceAction { id: "NewSsh", label_key: "settings_new_ssh", @@ -198,6 +204,7 @@ pub(crate) fn unbind_all_workspace_keys(cx: &mut App, config: &ConfigStore) { unbind_action!("OpenSettings", crate::OpenSettings); unbind_action!("OpenSession", crate::OpenSession); + unbind_action!("OpenTransfers", crate::OpenTransfers); unbind_action!("NewSsh", crate::NewSsh); unbind_action!("ToggleSidebar", crate::ToggleSidebar); unbind_action!("ToggleSftpZoom", crate::ToggleSftpZoom); @@ -252,6 +259,7 @@ fn bind_workspace_actions(cx: &mut App, config: &ConfigStore) { bind_action!("OpenSettings", crate::OpenSettings); bind_action!("OpenSession", crate::OpenSession); + bind_action!("OpenTransfers", crate::OpenTransfers); bind_action!("NewSsh", crate::NewSsh); bind_action!("ToggleSidebar", crate::ToggleSidebar); bind_action!("ToggleSftpZoom", crate::ToggleSftpZoom); @@ -273,7 +281,7 @@ impl KeybindingsPage { let groups = [ ( "settings_group_keybind_general", - vec!["OpenSettings", "OpenSession", "NewSsh"], + vec!["OpenSettings", "OpenSession", "OpenTransfers", "NewSsh"], ), ( "settings_group_keybind_zoom", diff --git a/src/app/mod.rs b/src/app/mod.rs index 4146b71..b5c979e 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -189,6 +189,14 @@ impl ScrollbarHandle for TerminalScrollbarHandle { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum DialogKind { + Settings, + SessionSelector, + Transfers, + NewSsh, +} + pub(crate) struct Ashell { pub(crate) focus_handle: FocusHandle, pub(crate) selector_focus_handle: FocusHandle, @@ -252,6 +260,7 @@ pub(crate) struct Ashell { pub(crate) config: ConfigStore, pub(crate) system_sampler: SystemSampler, pub(crate) recording_action: Option, + pub(crate) active_dialog: Option, /// Error message when a recorded keybinding conflicts with another pub(crate) keybind_error: Option<(String, String)>, // (action_id, error_message) /// Whether workspace keybindings are currently suspended (during settings) @@ -468,7 +477,7 @@ impl Ashell { terminal_marked_text: None, dragging_splitter: None, drag_split_origin: None, - sftp_panel_minimized: config.sftp_panel_minimized(), + sftp_panel_minimized: false, sidebar_collapsed: config.sidebar_collapsed(), collapsed_saved_scroll_handle: gpui::ScrollHandle::new(), prev_monitoring_size: None, @@ -476,6 +485,7 @@ impl Ashell { config, system_sampler, recording_action: None, + active_dialog: None, keybind_error: None, keybinds_suspended: false, system, diff --git a/src/app/startup.rs b/src/app/startup.rs index 255b4e1..32424b4 100644 --- a/src/app/startup.rs +++ b/src/app/startup.rs @@ -239,6 +239,20 @@ pub(crate) fn open_main_window(cx: &mut App) { let view = cx.new(|cx| Ashell::new(window, cx)); tracing::info!("[ui] main application window opened"); + let focus_handle = view.read(cx).focus_handle.clone(); + window.focus(&focus_handle, cx); + + let sftp_minimized = view.read(cx).config.sftp_panel_minimized(); + if sftp_minimized { + window.defer(cx, { + let view = view.clone(); + move |window, cx| { + view.update(cx, |this, cx| { + this.toggle_sftp_minimized(window, cx); + }); + } + }); + } let workspace_panels_clone = view.read(cx).workspace_panels.clone(); let body_panels_clone = view.read(cx).body_panels.clone(); @@ -283,12 +297,21 @@ pub(crate) fn open_main_window(cx: &mut App) { .iter() .map(|s| s.into()) .collect(); - let body_sizes: Vec = body_panels_clone + let mut body_sizes: Vec = body_panels_clone .read(cx) .sizes() .iter() .map(|s| s.into()) .collect(); + + if view_clone.read(cx).sftp_panel_minimized { + if let Some(prev) = view_clone.read(cx).prev_monitoring_size { + if body_sizes.len() > 1 { + body_sizes[1] = prev.into(); + } + } + } + config.set_layout_state(Some(saved_bounds), Some(workspace_sizes), Some(body_sizes)); config.set_sidebar_collapsed(view_clone.read(cx).sidebar_collapsed); config.set_sftp_panel_minimized(view_clone.read(cx).sftp_panel_minimized); diff --git a/src/app/ui.rs b/src/app/ui.rs index 5dd6001..84f9719 100644 --- a/src/app/ui.rs +++ b/src/app/ui.rs @@ -160,10 +160,10 @@ impl Ashell { }; let label = match kind { crate::terminal::TransferType::Download => { - format!("{} files downloading", active.len()) + t!("files_downloading", count = active.len()).to_string() } crate::terminal::TransferType::Upload => { - format!("{} files uploading", active.len()) + t!("files_uploading", count = active.len()).to_string() } }; match pct { @@ -286,7 +286,6 @@ impl Ashell { })), ) }); - let Some(sftp) = active_sftp else { let mut outer = v_flex() .gap_0() @@ -379,13 +378,17 @@ impl Ashell { ); } this.child(content) + .on_click(cx.listener(|this, _, window, cx| { + this.show_transfers_dialog(window, cx); + })) }) .when(!has_transfers, |this| { this.icon(IconName::ArrowDown) - }) - .on_click(cx.listener(|this, _, window, cx| { - this.show_transfers_dialog(window, cx); - })), + .label(t!("transfers").to_string()) + .on_click(cx.listener(|this, _, window, cx| { + this.show_transfers_dialog(window, cx); + })) + }), ) .child( Button::new("sftp-minimize-toggle") @@ -396,6 +399,11 @@ impl Ashell { } else { IconName::ChevronDown }) + .label(if self.sftp_panel_minimized { + t!("panel_expand").to_string() + } else { + t!("panel_minimize").to_string() + }) .on_click(cx.listener(|this, _, window, cx| { this.toggle_sftp_minimized(window, cx); })), @@ -788,11 +796,14 @@ impl Ashell { }) .when(!has_transfers, |this| { this.icon(IconName::ArrowDown) + .label(t!("transfers").to_string()) }) .on_click(cx.listener(|this, _, window, cx| { this.show_transfers_dialog(window, cx); })), + ) + .child( Button::new("sftp-minimize-toggle") .ghost() @@ -802,10 +813,17 @@ impl Ashell { } else { IconName::ChevronDown }) + .label(if self.sftp_panel_minimized { + t!("panel_expand").to_string() + } else { + t!("panel_minimize").to_string() + }) .on_click(cx.listener(|this, _, window, cx| { this.toggle_sftp_minimized(window, cx); })), + ), + ); outer.into_any_element() @@ -2447,6 +2465,7 @@ impl Render for Ashell { .font_family(self.ui_font_family.clone()) .on_action(cx.listener(|this, _: &crate::OpenSettings, window, cx| this.show_settings_dialog(window, cx))) .on_action(cx.listener(|this, _: &crate::OpenSession, window, cx| this.show_selector_dialog(window, cx))) + .on_action(cx.listener(|this, _: &crate::OpenTransfers, window, cx| this.show_transfers_dialog(window, cx))) .on_action(cx.listener(|this, _: &crate::NewSsh, window, cx| this.show_ssh_dialog(window, cx))) .on_action(cx.listener(|this, _: &crate::ToggleSidebar, _, cx| { this.sidebar_collapsed = !this.sidebar_collapsed; diff --git a/src/main.rs b/src/main.rs index de3132c..57b06ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,8 +16,8 @@ gpui::actions!(ashell_terminal, [TerminalTabKey, TerminalBacktabKey]); pub(crate) use app::keybinding_recorder::{ ClosePane, FocusPaneDown, FocusPaneLeft, FocusPaneRight, FocusPaneUp, NewSsh, OpenSession, - OpenSettings, SplitPaneDown, SplitPaneLeft, SplitPaneRight, SplitPaneUp, ToggleSftpZoom, - ToggleSidebar, + OpenSettings, OpenTransfers, SplitPaneDown, SplitPaneLeft, SplitPaneRight, SplitPaneUp, + ToggleSftpZoom, ToggleSidebar, }; pub(crate) use app::{