UI redesign: onboarding card, browser tabs, accent colors, clean toolbar
This commit is contained in:
parent
500da04ce7
commit
46514298cd
7 changed files with 113 additions and 183 deletions
|
|
@ -1,15 +1,12 @@
|
|||
use crate::domain::transfer::TransferTask;
|
||||
use crate::ui::panels::file_pane::format_size;
|
||||
use crate::ui::state::AppState;
|
||||
use egui::Color32;
|
||||
|
||||
pub fn render(ui: &mut egui::Ui, state: &mut AppState, tasks: &[TransferTask]) {
|
||||
pub fn render(ui: &mut egui::Ui, _state: &mut AppState, tasks: &[TransferTask]) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.heading("\u{1F4E6} Transfer Queue");
|
||||
ui.strong("Transfer Queue");
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
if ui.small_button("\u{2715}").clicked() {
|
||||
state.show_queue = false;
|
||||
}
|
||||
ui.label(format!("{} tasks", tasks.len()));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -27,13 +24,15 @@ pub fn render(ui: &mut egui::Ui, state: &mut AppState, tasks: &[TransferTask]) {
|
|||
for task in tasks {
|
||||
let bg = match &task.state {
|
||||
crate::domain::transfer::TaskState::Completed => {
|
||||
Color32::from_rgb(220, 255, 220)
|
||||
egui::Color32::from_rgb(220, 255, 220)
|
||||
}
|
||||
crate::domain::transfer::TaskState::Failed(_) => {
|
||||
Color32::from_rgb(255, 220, 220)
|
||||
egui::Color32::from_rgb(255, 220, 220)
|
||||
}
|
||||
crate::domain::transfer::TaskState::Running => Color32::from_rgb(220, 220, 255),
|
||||
_ => Color32::TRANSPARENT,
|
||||
crate::domain::transfer::TaskState::Running => {
|
||||
egui::Color32::from_rgb(220, 220, 255)
|
||||
}
|
||||
_ => egui::Color32::TRANSPARENT,
|
||||
};
|
||||
|
||||
egui::Frame::none()
|
||||
|
|
@ -59,6 +58,7 @@ pub fn render(ui: &mut egui::Ui, state: &mut AppState, tasks: &[TransferTask]) {
|
|||
let pct = task.progress_pct();
|
||||
let pb = egui::ProgressBar::new(pct as f32 / 100.0)
|
||||
.text(format!("{:.1}%", pct))
|
||||
.fill(egui::Color32::from_rgb(100, 80, 220))
|
||||
.desired_width(ui.available_width() * 0.6);
|
||||
ui.add(pb);
|
||||
|
||||
|
|
|
|||
|
|
@ -193,8 +193,9 @@ pub fn trigger_list(
|
|||
let path = state.tabs[tab_idx].remote_path.clone();
|
||||
let registry = registry.clone();
|
||||
|
||||
let result: Arc<std::sync::Mutex<Option<Result<Vec<FileEntry>, String>>>> =
|
||||
Arc::new(std::sync::Mutex::new(None));
|
||||
let result = Arc::new(std::sync::Mutex::new(
|
||||
None::<Result<Vec<FileEntry>, String>>,
|
||||
));
|
||||
let result_clone = result.clone();
|
||||
|
||||
rt_handle.spawn(async move {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
use crate::domain::connection::ConnectionStatus;
|
||||
use crate::ui::state::AppState;
|
||||
|
||||
pub fn render(ui: &mut egui::Ui, state: &AppState) {
|
||||
pub fn render(ui: &mut egui::Ui, state: &mut AppState) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(&state.status_message);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
let queued = state.queue_tasks.len();
|
||||
ui.label(format!("Queue: {}", queued));
|
||||
let queue_label = if state.show_queue {
|
||||
format!("Queue ({}) \u{25BC}", queued)
|
||||
} else {
|
||||
format!("Queue ({}) \u{25B2}", queued)
|
||||
};
|
||||
if ui.button(queue_label).clicked() {
|
||||
state.show_queue = !state.show_queue;
|
||||
}
|
||||
ui.separator();
|
||||
let connected = state
|
||||
.tabs
|
||||
|
|
@ -14,7 +21,7 @@ pub fn render(ui: &mut egui::Ui, state: &AppState) {
|
|||
.filter(|t| t.status == ConnectionStatus::Connected)
|
||||
.count();
|
||||
let total = state.tabs.len();
|
||||
ui.label(format!("Connections: {}/{}", connected, total));
|
||||
ui.label(format!("{}/{}", connected, total));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
use crate::domain::connection::ConnectionStatus;
|
||||
use crate::ui::state::AppState;
|
||||
|
||||
const ACCENT: egui::Color32 = egui::Color32::from_rgb(100, 80, 220);
|
||||
|
||||
pub fn render(ui: &mut egui::Ui, state: &mut AppState) {
|
||||
ui.horizontal(|ui| {
|
||||
if state.tabs.is_empty() {
|
||||
ui.label("No connections");
|
||||
if ui.button("+ New Connection").clicked() {
|
||||
state.show_connect_dialog = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let mut to_close: Option<usize> = None;
|
||||
|
||||
for (i, tab) in state.tabs.iter().enumerate() {
|
||||
|
|
@ -23,18 +17,18 @@ pub fn render(ui: &mut egui::Ui, state: &mut AppState) {
|
|||
ConnectionStatus::Error(_) => "\u{2716}",
|
||||
};
|
||||
|
||||
let label = format!("{} {}", dot, tab.label);
|
||||
let label = format!("{} {} ", dot, tab.label);
|
||||
|
||||
let mut tab_button = egui::Button::new(&label);
|
||||
let mut tab_btn = egui::Button::new(&label)
|
||||
.min_size(egui::vec2(60.0, 28.0));
|
||||
if is_active {
|
||||
tab_button = tab_button.fill(egui::Color32::from_rgb(60, 60, 80));
|
||||
tab_btn = tab_btn.fill(ACCENT);
|
||||
}
|
||||
let response = ui.add(tab_button);
|
||||
if response.clicked() {
|
||||
if ui.add(tab_btn).clicked() {
|
||||
state.active_tab = i;
|
||||
}
|
||||
|
||||
if ui.small_button("\u{2715}").clicked() {
|
||||
if ui.small_button("x").clicked() {
|
||||
to_close = Some(i);
|
||||
}
|
||||
}
|
||||
|
|
@ -46,8 +40,6 @@ pub fn render(ui: &mut egui::Ui, state: &mut AppState) {
|
|||
}
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
|
||||
if ui.button("+").clicked() {
|
||||
state.show_connect_dialog = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,139 +1,11 @@
|
|||
use crate::domain::connection::ConnectionStatus;
|
||||
use crate::domain::file_entry::EntryKind;
|
||||
use crate::domain::transfer::{TransferKind, TransferTask};
|
||||
use crate::fs::remote::RemoteRegistry;
|
||||
use crate::transfer::queue::TransferQueue;
|
||||
use crate::ui::state::AppState;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn render(
|
||||
ui: &mut egui::Ui,
|
||||
state: &mut AppState,
|
||||
queue: &TransferQueue,
|
||||
registry: &Arc<RemoteRegistry>,
|
||||
_rt_handle: &tokio::runtime::Handle,
|
||||
) {
|
||||
pub fn render(ui: &mut egui::Ui, state: &mut AppState) {
|
||||
ui.horizontal(|ui| {
|
||||
let add_btn = egui::Button::new("+ New Connection");
|
||||
let add_btn = egui::Button::new("+ New Connection")
|
||||
.fill(egui::Color32::from_rgb(80, 60, 180));
|
||||
if ui.add(add_btn).clicked() {
|
||||
state.show_connect_dialog = true;
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
|
||||
let has_local_selection = state.local_selected.is_some();
|
||||
let has_remote_selection = state
|
||||
.active_tab_ref()
|
||||
.and_then(|t| t.remote_selected.as_ref())
|
||||
.is_some();
|
||||
let (is_connected, tab_exists) = {
|
||||
let active = state.active_tab_ref();
|
||||
(
|
||||
active
|
||||
.map(|t| t.status == ConnectionStatus::Connected)
|
||||
.unwrap_or(false),
|
||||
active.is_some(),
|
||||
)
|
||||
};
|
||||
|
||||
let tab_id = state.active_tab_ref().map(|t| t.id.clone());
|
||||
let remote_path = state.active_tab_ref().map(|t| t.remote_path.clone());
|
||||
|
||||
let upload_btn = egui::Button::new("\u{2191} Upload")
|
||||
.min_size(egui::vec2(100.0, 24.0));
|
||||
ui.add_enabled_ui(is_connected && has_local_selection && tab_exists, |ui| {
|
||||
if ui.add(upload_btn).clicked()
|
||||
&& let Some(sel) = state.local_selected.clone()
|
||||
&& let Some(entry) = state.local_entries.iter().find(|e| e.name == sel)
|
||||
{
|
||||
if entry.kind == EntryKind::File {
|
||||
let file_name = entry.name.clone();
|
||||
let remote_base = remote_path.clone().unwrap_or_else(|| "/".into());
|
||||
let remote_path_str =
|
||||
format!("{}/{}", remote_base.trim_end_matches('/'), file_name);
|
||||
let cid = tab_id.clone().unwrap_or_default();
|
||||
let task = TransferTask::new(
|
||||
TransferKind::Upload,
|
||||
cid,
|
||||
entry.path.clone(),
|
||||
remote_path_str,
|
||||
file_name,
|
||||
entry.size.unwrap_or(0),
|
||||
);
|
||||
if registry.get(&task.connection_id).is_some() {
|
||||
queue.push(task);
|
||||
state.status_message = "Upload queued".into();
|
||||
} else {
|
||||
state.status_message = "No connection".into();
|
||||
}
|
||||
} else {
|
||||
state.status_message = "Cannot upload directory".into();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let download_btn = egui::Button::new("\u{2193} Download")
|
||||
.min_size(egui::vec2(100.0, 24.0));
|
||||
ui.add_enabled_ui(is_connected && has_remote_selection && tab_exists, |ui| {
|
||||
if ui.add(download_btn).clicked()
|
||||
&& let Some(sel) = tab_remote_selected(state)
|
||||
{
|
||||
let file_name = sel.clone();
|
||||
let remote_base = remote_path.clone().unwrap_or_else(|| "/".into());
|
||||
let remote_path_str =
|
||||
format!("{}/{}", remote_base.trim_end_matches('/'), file_name);
|
||||
let local_path_str =
|
||||
format!("{}/{}", state.local_path.trim_end_matches('/'), file_name);
|
||||
let size = state
|
||||
.active_tab_ref()
|
||||
.map(|t| {
|
||||
t.remote_entries
|
||||
.iter()
|
||||
.find(|e| e.name == sel)
|
||||
.and_then(|e| e.size)
|
||||
.unwrap_or(0)
|
||||
})
|
||||
.unwrap_or(0);
|
||||
let cid = tab_id.clone().unwrap_or_default();
|
||||
let task = TransferTask::new(
|
||||
TransferKind::Download,
|
||||
cid,
|
||||
local_path_str,
|
||||
remote_path_str,
|
||||
file_name,
|
||||
size,
|
||||
);
|
||||
if registry.get(&task.connection_id).is_some() {
|
||||
queue.push(task);
|
||||
state.status_message = "Download queued".into();
|
||||
} else {
|
||||
state.status_message = "No connection".into();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
||||
let queue_label = if state.show_queue {
|
||||
"Queue \u{25BC}"
|
||||
} else {
|
||||
"Queue \u{25B2}"
|
||||
};
|
||||
if ui.button(queue_label).clicked() {
|
||||
state.show_queue = !state.show_queue;
|
||||
}
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
ui.separator();
|
||||
let task_count = state.queue_tasks.len();
|
||||
if task_count > 0 {
|
||||
ui.label(format!("{} tasks", task_count));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn tab_remote_selected(state: &AppState) -> Option<String> {
|
||||
let idx = state.active_tab.min(state.tabs.len().saturating_sub(1));
|
||||
state.tabs.get(idx).and_then(|t| t.remote_selected.clone())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue