Completely eliminate panel separation gap with unified horizontal container in v2.5.5

This commit is contained in:
RarDog
2026-08-28 14:29:55 +03:00
parent 3ca52e2649
commit d4f52e3ec6
+114 -97
View File
@@ -16,7 +16,7 @@ use crate::updater::{
}; };
use eframe::egui::{ use eframe::egui::{
self, Align, Button, CentralPanel, Color32, ColorImage, Frame, Layout, Margin, ProgressBar, self, Align, Button, CentralPanel, Color32, ColorImage, Frame, Layout, Margin, ProgressBar,
RichText, Rounding, ScrollArea, SidePanel, Stroke, TextureHandle, TextureOptions, Ui, Vec2, RichText, Rounding, ScrollArea, Stroke, TextureHandle, TextureOptions, Ui, Vec2,
}; };
use human_bytes::human_bytes; use human_bytes::human_bytes;
use qrcode::{Color as QrColor, QrCode}; use qrcode::{Color as QrColor, QrCode};
@@ -5020,114 +5020,131 @@ impl eframe::App for ZeroSendApp {
style.visuals.widgets.active.rounding = Rounding::same(6.0); style.visuals.widgets.active.rounding = Rounding::same(6.0);
ctx.set_style(style); ctx.set_style(style);
SidePanel::left("sidebar_panel")
.resizable(false)
.show_separator_line(false)
.exact_width(200.0)
.frame(
Frame::none()
.fill(theme.bg_sidebar)
.inner_margin(Margin::same(12.0)),
)
.show(ctx, |ui| {
self.render_sidebar(ctx, ui, theme);
});
CentralPanel::default() CentralPanel::default()
.frame( .frame(
Frame::none() Frame::none()
.fill(theme.bg_app) .fill(theme.bg_app)
.inner_margin(Margin::same(20.0)), .inner_margin(Margin::ZERO),
) )
.show(ctx, |ui| { .show(ctx, |ui| {
// Top Update Banner if update available on Gitea ui.spacing_mut().item_spacing = Vec2::ZERO;
if self.show_update_banner {
if let Some(info) = &self.update_info {
if info.has_update {
let mut dismiss = false;
let mut trigger_install = None;
let mut open_gitea = false;
let gitea_url = info.gitea_url.clone();
let latest_ver = info.latest_version.clone();
let download_url = info.download_url.clone();
Frame::none() ui.horizontal(|ui| {
.fill(if theme.is_dark { Color32::from_rgb(17, 43, 31) } else { Color32::from_rgb(220, 252, 231) }) // ── Left Sidebar (200px) ──
.stroke(Stroke::new(1.0_f32, Color32::from_rgb(34, 197, 94))) ui.allocate_ui(Vec2::new(200.0, ui.available_height()), |ui| {
.rounding(Rounding::same(8.0)) Frame::none()
.inner_margin(Margin::symmetric(14.0, 10.0)) .fill(theme.bg_sidebar)
.show(ui, |ui| { .inner_margin(Margin::same(12.0))
ui.horizontal(|ui| { .show(ui, |ui| {
ui.label(RichText::new("✨").size(16.0)); ui.set_min_width(176.0);
ui.label( ui.set_min_height(ui.available_height());
RichText::new(format!("Update Available: ZeroSend v{} is out on Gitea!", latest_ver)) self.render_sidebar(ctx, ui, theme);
.strong() });
.color(if theme.is_dark { Color32::WHITE } else { Color32::from_rgb(20, 83, 45) }) });
);
ui.with_layout(Layout::right_to_left(Align::Center), |ui| { // ── Right Main Content Area ──
if ui.button(RichText::new("✕").size(12.0).color(theme.text_muted)).clicked() { let content_width = ui.available_width();
dismiss = true; let content_height = ui.available_height();
ui.allocate_ui(Vec2::new(content_width, content_height), |ui| {
Frame::none()
.fill(theme.bg_app)
.inner_margin(Margin::same(20.0))
.show(ui, |ui| {
ui.set_min_width(content_width - 40.0);
ui.set_min_height(content_height - 40.0);
ui.spacing_mut().item_spacing = Vec2::new(8.0, 8.0);
// Top Update Banner if update available on Gitea
if self.show_update_banner {
if let Some(info) = &self.update_info {
if info.has_update {
let mut dismiss = false;
let mut trigger_install = None;
let mut open_gitea = false;
let gitea_url = info.gitea_url.clone();
let latest_ver = info.latest_version.clone();
let download_url = info.download_url.clone();
Frame::none()
.fill(if theme.is_dark { Color32::from_rgb(17, 43, 31) } else { Color32::from_rgb(220, 252, 231) })
.stroke(Stroke::new(1.0_f32, Color32::from_rgb(34, 197, 94)))
.rounding(Rounding::same(8.0))
.inner_margin(Margin::symmetric(14.0, 10.0))
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.label(RichText::new("✨").size(16.0));
ui.label(
RichText::new(format!("Update Available: ZeroSend v{} is out on Gitea!", latest_ver))
.strong()
.color(if theme.is_dark { Color32::WHITE } else { Color32::from_rgb(20, 83, 45) })
);
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
if ui.button(RichText::new("✕").size(12.0).color(theme.text_muted)).clicked() {
dismiss = true;
}
if ui.button(RichText::new("🌐 View on Gitea").size(11.5)).clicked() {
open_gitea = true;
}
if let Some(dl) = download_url {
if !self.is_updating {
let update_btn = Button::new(
RichText::new("🚀 Update Now").strong().size(12.0).color(Color32::WHITE)
)
.fill(Color32::from_rgb(34, 197, 94))
.rounding(Rounding::same(6.0));
if ui.add(update_btn).clicked() {
trigger_install = Some(dl);
}
} else {
ui.label(RichText::new("⏳ Updating...").color(Color32::from_rgb(34, 197, 94)).strong());
}
}
});
});
});
if dismiss {
self.show_update_banner = false;
}
if open_gitea {
let _ = std::process::Command::new("explorer").arg(&gitea_url).spawn();
}
if let Some(dl) = trigger_install {
self.trigger_install_update(dl);
} }
if ui.button(RichText::new("🌐 View on Gitea").size(11.5)).clicked() { ui.add_space(10.0);
open_gitea = true; }
} }
}
if let Some(dl) = download_url { // Fluid Tab Transition Animation (Smooth Slide-in & Fade-in)
if !self.is_updating { let elapsed = self.last_tab_change.elapsed().as_secs_f32();
let update_btn = Button::new( let duration = 0.20; // 200 ms
RichText::new("🚀 Update Now").strong().size(12.0).color(Color32::WHITE) let progress = (elapsed / duration).min(1.0);
) if progress < 1.0 {
.fill(Color32::from_rgb(34, 197, 94)) ctx.request_repaint();
.rounding(Rounding::same(6.0)); }
// Cubic ease-out curve
let ease = 1.0 - (1.0 - progress).powi(3);
let slide_offset = (1.0 - ease) * 12.0;
ui.add_space(slide_offset);
if ui.add(update_btn).clicked() { match self.current_tab {
trigger_install = Some(dl); Tab::Nearby => self.render_nearby_tab(ui, theme),
} Tab::Send => self.render_send_tab(ui, theme),
} else { Tab::Receive => self.render_receive_tab(ui, theme),
ui.label(RichText::new("⏳ Updating...").color(Color32::from_rgb(34, 197, 94)).strong()); Tab::Shared => self.render_shared_tab(ui, theme),
} Tab::Transfers => self.render_transfers_tab(ui, theme),
} Tab::Settings => self.render_settings_tab(ui, theme),
}); }
}); });
}); });
});
if dismiss {
self.show_update_banner = false;
}
if open_gitea {
let _ = std::process::Command::new("explorer").arg(&gitea_url).spawn();
}
if let Some(dl) = trigger_install {
self.trigger_install_update(dl);
}
ui.add_space(10.0);
}
}
}
// Fluid Tab Transition Animation (Smooth Slide-in & Fade-in)
let elapsed = self.last_tab_change.elapsed().as_secs_f32();
let duration = 0.20; // 200 ms
let progress = (elapsed / duration).min(1.0);
if progress < 1.0 {
ctx.request_repaint();
}
// Cubic ease-out curve
let ease = 1.0 - (1.0 - progress).powi(3);
let slide_offset = (1.0 - ease) * 12.0;
ui.add_space(slide_offset);
match self.current_tab {
Tab::Nearby => self.render_nearby_tab(ui, theme),
Tab::Send => self.render_send_tab(ui, theme),
Tab::Receive => self.render_receive_tab(ui, theme),
Tab::Shared => self.render_shared_tab(ui, theme),
Tab::Transfers => self.render_transfers_tab(ui, theme),
Tab::Settings => self.render_settings_tab(ui, theme),
}
}); });
self.render_modals(ctx, theme); self.render_modals(ctx, theme);