Implement condensed list view

This commit is contained in:
Jeremy Soller 2024-02-29 19:47:27 -07:00
parent d485e51acb
commit f8521d5b0d
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
4 changed files with 113 additions and 59 deletions

View file

@ -546,7 +546,10 @@ impl Application for App {
} }
/// Creates the application, and optionally emits command on initialize. /// Creates the application, and optionally emits command on initialize.
fn init(core: Core, flags: Self::Flags) -> (Self, Command<Self::Message>) { fn init(mut core: Core, flags: Self::Flags) -> (Self, Command<Self::Message>) {
//TODO: make set_nav_bar_toggle_condensed pub
core.nav_bar_toggle_condensed();
let app_themes = vec![fl!("match-desktop"), fl!("dark"), fl!("light")]; let app_themes = vec![fl!("match-desktop"), fl!("dark"), fl!("light")];
let mut nav_model = segmented_button::ModelBuilder::default(); let mut nav_model = segmented_button::ModelBuilder::default();

View file

@ -12,6 +12,7 @@ pub const CONFIG_VERSION: u64 = 1;
// Default icon sizes // Default icon sizes
const ICON_SIZE_LIST: u16 = 24; const ICON_SIZE_LIST: u16 = 24;
const ICON_SIZE_LIST_CONDENSED: u16 = 48;
const ICON_SIZE_GRID: u16 = 64; const ICON_SIZE_GRID: u16 = 64;
// TODO: 5 is an arbitrary number. Maybe there's a better icon size max // TODO: 5 is an arbitrary number. Maybe there's a better icon size max
const ICON_SCALE_MAX: u16 = 5; const ICON_SCALE_MAX: u16 = 5;
@ -98,6 +99,10 @@ impl IconSizes {
percent!(self.list, ICON_SIZE_LIST) as _ percent!(self.list, ICON_SIZE_LIST) as _
} }
pub fn list_condensed(&self) -> u16 {
percent!(self.list, ICON_SIZE_LIST_CONDENSED) as _
}
pub fn grid(&self) -> u16 { pub fn grid(&self) -> u16 {
percent!(self.grid, ICON_SIZE_GRID) as _ percent!(self.grid, ICON_SIZE_GRID) as _
} }

View file

@ -312,6 +312,8 @@ impl Application for App {
fn init(mut core: Core, flags: Self::Flags) -> (Self, Command<Message>) { fn init(mut core: Core, flags: Self::Flags) -> (Self, Command<Message>) {
core.window.show_maximize = false; core.window.show_maximize = false;
core.window.show_minimize = false; core.window.show_minimize = false;
//TODO: make set_nav_bar_toggle_condensed pub
core.nav_bar_toggle_condensed();
let mut nav_model = segmented_button::ModelBuilder::default(); let mut nav_model = segmented_button::ModelBuilder::default();
if let Some(dir) = dirs::home_dir() { if let Some(dir) = dirs::home_dir() {

View file

@ -226,17 +226,20 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
let mime_guess = MimeGuess::from_path(&path); let mime_guess = MimeGuess::from_path(&path);
let (icon_handle_grid, icon_handle_list) = if metadata.is_dir() { let (icon_handle_grid, icon_handle_list, icon_handle_list_condensed) =
( if metadata.is_dir() {
folder_icon(&path, sizes.grid()), (
folder_icon(&path, sizes.list()), folder_icon(&path, sizes.grid()),
) folder_icon(&path, sizes.list()),
} else { folder_icon(&path, sizes.list_condensed()),
( )
mime_icon(&path, sizes.grid()), } else {
mime_icon(&path, sizes.list()), (
) mime_icon(&path, sizes.grid()),
}; mime_icon(&path, sizes.list()),
mime_icon(&path, sizes.list_condensed()),
)
};
let children = if metadata.is_dir() { let children = if metadata.is_dir() {
//TODO: calculate children in the background (and make it cancellable?) //TODO: calculate children in the background (and make it cancellable?)
@ -259,6 +262,7 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
mime_guess, mime_guess,
icon_handle_grid, icon_handle_grid,
icon_handle_list, icon_handle_list,
icon_handle_list_condensed,
thumbnail_res_opt: match mime_guess.first() { thumbnail_res_opt: match mime_guess.first() {
Some(mime) if mime.type_() == "image" => None, Some(mime) if mime.type_() == "image" => None,
_ => Some(Err(())), _ => Some(Err(())),
@ -326,16 +330,19 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
let mime_guess = MimeGuess::from_path(&path); let mime_guess = MimeGuess::from_path(&path);
let (icon_handle_grid, icon_handle_list) = match metadata.size { let (icon_handle_grid, icon_handle_list, icon_handle_list_condensed) =
trash::TrashItemSize::Entries(_) => ( match metadata.size {
folder_icon(&path, sizes.grid()), trash::TrashItemSize::Entries(_) => (
folder_icon(&path, sizes.list()), folder_icon(&path, sizes.grid()),
), folder_icon(&path, sizes.list()),
trash::TrashItemSize::Bytes(_) => ( folder_icon(&path, sizes.list_condensed()),
mime_icon(&path, sizes.grid()), ),
mime_icon(&path, sizes.list()), trash::TrashItemSize::Bytes(_) => (
), mime_icon(&path, sizes.grid()),
}; mime_icon(&path, sizes.list()),
mime_icon(&path, sizes.list_condensed()),
),
};
items.push(Item { items.push(Item {
name, name,
@ -345,6 +352,7 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
mime_guess, mime_guess,
icon_handle_grid, icon_handle_grid,
icon_handle_list, icon_handle_list,
icon_handle_list_condensed,
thumbnail_res_opt: Some(Err(())), thumbnail_res_opt: Some(Err(())),
button_id: widget::Id::unique(), button_id: widget::Id::unique(),
pos_opt: Cell::new(None), pos_opt: Cell::new(None),
@ -450,6 +458,7 @@ pub struct Item {
pub mime_guess: MimeGuess, pub mime_guess: MimeGuess,
pub icon_handle_grid: widget::icon::Handle, pub icon_handle_grid: widget::icon::Handle,
pub icon_handle_list: widget::icon::Handle, pub icon_handle_list: widget::icon::Handle,
pub icon_handle_list_condensed: widget::icon::Handle,
pub thumbnail_res_opt: Option<Result<image::RgbaImage, ()>>, pub thumbnail_res_opt: Option<Result<image::RgbaImage, ()>>,
pub button_id: widget::Id, pub button_id: widget::Id,
pub pos_opt: Cell<Option<(usize, usize)>>, pub pos_opt: Cell<Option<(usize, usize)>>,
@ -1483,11 +1492,23 @@ impl Tab {
space_m, space_xxs, .. space_m, space_xxs, ..
} = theme::active().cosmic().spacing; } = theme::active().cosmic().spacing;
let TabConfig {
show_hidden,
icon_sizes,
} = self.config;
let size = self.size_opt.unwrap_or_else(|| Size::new(0.0, 0.0)); let size = self.size_opt.unwrap_or_else(|| Size::new(0.0, 0.0));
let row_height = 40; //TODO: allow resizing?
//TODO: make adaptive? let name_width = 300.0;
let modified_width = Length::Fixed(200.0); let modified_width = 200.0;
let size_width = Length::Fixed(100.0); let size_width = 100.0;
let condensed = size.width < (name_width + modified_width + size_width);
let icon_size = if condensed {
icon_sizes.list_condensed()
} else {
icon_sizes.list()
};
let row_height = icon_size + 2 * space_xxs;
let heading_item = |name, width, msg| { let heading_item = |name, width, msg| {
let mut row = widget::row::with_capacity(2) let mut row = widget::row::with_capacity(2)
@ -1511,31 +1532,33 @@ impl Tab {
}; };
let mut children: Vec<Element<_>> = Vec::new(); let mut children: Vec<Element<_>> = Vec::new();
children.push( let mut y = 0;
widget::row::with_children(vec![ if !condensed {
heading_item(fl!("name"), Length::Fill, HeadingOptions::Name), children.push(
//TODO: do not show modified column when in the trash widget::row::with_children(vec![
heading_item(fl!("modified"), modified_width, HeadingOptions::Modified), heading_item(fl!("name"), Length::Fill, HeadingOptions::Name),
heading_item(fl!("size"), size_width, HeadingOptions::Size), //TODO: do not show modified column when in the trash
]) heading_item(
.align_items(Alignment::Center) fl!("modified"),
.height(Length::Fixed(row_height as f32)) Length::Fixed(modified_width),
.padding(space_xxs) HeadingOptions::Modified,
.spacing(space_xxs) ),
.into(), heading_item(fl!("size"), Length::Fixed(size_width), HeadingOptions::Size),
); ])
let mut y = row_height; .align_items(Alignment::Center)
.height(Length::Fixed(row_height as f32))
children.push(horizontal_rule(1).into()); .padding(space_xxs)
y += 1; .spacing(space_xxs)
.into(),
);
y += row_height;
children.push(horizontal_rule(1).into());
y += 1;
}
if let Some(items) = self.column_sort() { if let Some(items) = self.column_sort() {
let mut count = 0; let mut count = 0;
let mut hidden = 0; let mut hidden = 0;
let TabConfig {
show_hidden,
icon_sizes,
} = self.config;
for (i, item) in items { for (i, item) in items {
if !show_hidden && item.hidden { if !show_hidden && item.hidden {
item.pos_opt.set(None); item.pos_opt.set(None);
@ -1585,25 +1608,46 @@ impl Tab {
}, },
}; };
//TODO: align columns let row = if condensed {
let button = widget::button( widget::row::with_children(vec![
widget::icon::icon(item.icon_handle_list_condensed.clone())
.content_fit(ContentFit::Contain)
.size(icon_size)
.into(),
widget::column::with_children(vec![
widget::text(item.name.clone()).into(),
//TODO: translate?
widget::text(format!("{} - {}", modified_text, size_text)).into(),
])
.into(),
])
.align_items(Alignment::Center)
.spacing(space_xxs)
} else {
widget::row::with_children(vec![ widget::row::with_children(vec![
widget::icon::icon(item.icon_handle_list.clone()) widget::icon::icon(item.icon_handle_list.clone())
.content_fit(ContentFit::Contain) .content_fit(ContentFit::Contain)
.size(icon_sizes.list()) .size(icon_size)
.into(), .into(),
widget::text(item.name.clone()).width(Length::Fill).into(), widget::text(item.name.clone()).width(Length::Fill).into(),
widget::text(modified_text).width(modified_width).into(), widget::text(modified_text)
widget::text(size_text).width(size_width).into(), .width(Length::Fixed(modified_width))
.into(),
widget::text(size_text)
.width(Length::Fixed(size_width))
.into(),
]) ])
.align_items(Alignment::Center) .align_items(Alignment::Center)
.spacing(space_xxs), .spacing(space_xxs)
) };
.height(Length::Fixed(row_height as f32))
.id(item.button_id.clone()) let button = widget::button(row)
.padding(space_xxs) .width(Length::Fill)
.style(button_style(item.selected, true)) .height(Length::Fixed(row_height as f32))
.on_press(Message::Click(Some(i))); .id(item.button_id.clone())
.padding(space_xxs)
.style(button_style(item.selected, true))
.on_press(Message::Click(Some(i)));
if self.context_menu.is_some() { if self.context_menu.is_some() {
children.push(button.into()); children.push(button.into());
} else { } else {