Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally restore last session #574

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions i18n/en/cosmic_files.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ match-desktop = Match desktop
dark = Dark
light = Light
### Session
session = Session
restore-session = Restore previous session on start
# Context menu
add-to-sidebar = Add to sidebar
compress = Compress
Expand Down
104 changes: 79 additions & 25 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ use wayland_client::{protocol::wl_output::WlOutput, Proxy};

use crate::{
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
config::{AppTheme, Config, DesktopConfig, Favorite, IconSizes, TabConfig},
config::{AppTheme, Config, DesktopConfig, Favorite, IconSizes, SessionConfig, TabConfig},
fl, home_dir,
key_bind::key_binds,
localize::LANGUAGE_SORTER,
Expand All @@ -69,7 +69,7 @@ use crate::{
tab::{self, HeadingOptions, ItemMetadata, Location, Tab, HOVER_DURATION},
};

#[derive(Clone, Debug)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Mode {
App,
Desktop,
Expand Down Expand Up @@ -303,9 +303,11 @@ pub enum Message {
Rename(Option<Entity>),
ReplaceResult(ReplaceResult),
RestoreFromTrash(Option<Entity>),
SaveSession,
SearchActivate,
SearchClear,
SearchInput(String),
SessionConfig(SessionConfig),
SystemThemeModeChange(cosmic_theme::ThemeMode),
TabActivate(Entity),
TabNext,
Expand Down Expand Up @@ -1179,27 +1181,43 @@ impl App {

fn settings(&self) -> Element<Message> {
// TODO: Should dialog be updated here too?
widget::settings::view_column(vec![widget::settings::section()
.title(fl!("appearance"))
.add({
let app_theme_selected = match self.config.app_theme {
AppTheme::Dark => 1,
AppTheme::Light => 2,
AppTheme::System => 0,
};
widget::settings::item::builder(fl!("theme")).control(widget::dropdown(
&self.app_themes,
Some(app_theme_selected),
move |index| {
Message::AppTheme(match index {
1 => AppTheme::Dark,
2 => AppTheme::Light,
_ => AppTheme::System,
})
},
))
})
.into()])
widget::settings::view_column(vec![
widget::settings::section()
.title(fl!("appearance"))
.add({
let app_theme_selected = match self.config.app_theme {
AppTheme::Dark => 1,
AppTheme::Light => 2,
AppTheme::System => 0,
};
widget::settings::item::builder(fl!("theme")).control(widget::dropdown(
&self.app_themes,
Some(app_theme_selected),
move |index| {
Message::AppTheme(match index {
1 => AppTheme::Dark,
2 => AppTheme::Light,
_ => AppTheme::System,
})
},
))
})
.into(),
widget::settings::section()
.title(fl!("session"))
.add(
widget::settings::item::builder(fl!("restore-session")).toggler(
self.config.session.restore,
move |restore| {
Message::SessionConfig(SessionConfig {
restore,
..Default::default()
})
},
),
)
.into(),
])
.into()
}
}
Expand Down Expand Up @@ -2355,6 +2373,35 @@ impl Application for App {
self.operation(Operation::Restore { paths });
}
}
Message::SaveSession => {
if self.config.session.restore && self.mode == Mode::App {
let session = SessionConfig {
tabs: Some(
self.tab_model
.iter()
.filter_map(|entity| {
match self
.tab_model
.data::<Tab>(entity)
.map(|tab| &tab.location)
{
// Location's serialization implementation skips variants
// such as mounts
// However, we'd still clone all Locations here only for
// some to be skipped, so it's best to avoid the clone
loc @ Location::Path(_)
| Location::Recents
| Location::Trash => Some(loc.clone()),
_ => None,
}
})
.collect(),
),
..self.config.session
};
config_set!(session, session);
}
}
Message::SearchActivate => {
return if self.search_get().is_none() {
self.search_set(Some(String::new()))
Expand All @@ -2368,6 +2415,9 @@ impl Application for App {
Message::SearchInput(input) => {
return self.search_set(Some(input));
}
Message::SessionConfig(session) => {
config_set!(session, session);
}
Message::SystemThemeModeChange(_theme_mode) => {
return self.update_config();
}
Expand Down Expand Up @@ -2435,9 +2485,12 @@ impl Application for App {
// Remove item
self.tab_model.remove(entity);

// If that was the last tab, close window
// If that was the last tab, close window and serialize empty session if necessary
if self.tab_model.iter().next().is_none() {
return window::close(window::Id::MAIN);
return Command::batch([
self.update(Message::SaveSession),
window::close(window::Id::MAIN),
]);
}

return Command::batch([self.update_title(), self.update_watcher()]);
Expand Down Expand Up @@ -2698,6 +2751,7 @@ impl Application for App {
if let Some(window_id) = self.window_id_opt.take() {
return Command::batch([
window::close(window_id),
self.update(Message::SaveSession),
Command::perform(async move { message::app(Message::MaybeExit) }, |x| x),
]);
}
Expand Down
13 changes: 12 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use cosmic::{
};
use serde::{Deserialize, Serialize};

use crate::{app::App, tab::View};
use crate::{
app::App,
tab::{Location, View},
};

pub const CONFIG_VERSION: u64 = 1;

Expand Down Expand Up @@ -97,6 +100,7 @@ pub struct Config {
pub favorites: Vec<Favorite>,
pub show_details: bool,
pub tab: TabConfig,
pub session: SessionConfig,
}

impl Config {
Expand Down Expand Up @@ -144,6 +148,7 @@ impl Default for Config {
],
show_details: false,
tab: TabConfig::default(),
session: SessionConfig::default(),
}
}
}
Expand Down Expand Up @@ -229,3 +234,9 @@ impl IconSizes {
percent!(self.grid, ICON_SIZE_GRID) as _
}
}

#[derive(Clone, Debug, Default, PartialEq, Eq, CosmicConfigEntry, Deserialize, Serialize)]
pub struct SessionConfig {
pub restore: bool,
pub tabs: Option<Vec<Location>>,
}
21 changes: 12 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,22 +96,25 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {

localize::localize();

let (config_handler, config) = Config::load();
let (config_handler, mut config) = Config::load();

let mut locations = Vec::new();
for arg in env::args().skip(1) {
let location = if &arg == "--trash" {
Location::Trash
} else {
match fs::canonicalize(&arg) {
Ok(absolute) => Location::Path(absolute),
match &*arg {
"--trash" => locations.push(Location::Trash),
// Override session regardless of config
"--no-session" => _ = config.session.tabs.take(),
path => match fs::canonicalize(path) {
Ok(absolute) => locations.push(Location::Path(absolute)),
Err(err) => {
log::warn!("failed to canonicalize {:?}: {}", arg, err);
continue;
}
}
};
locations.push(location);
}
}
}
if let Some(session) = config.session.restore.then(|| config.session.tabs.take()).flatten() {
locations.extend(session);
}

let mut settings = Settings::default();
Expand Down
5 changes: 4 additions & 1 deletion src/tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -861,12 +861,15 @@ pub fn scan_desktop(
items
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub enum Location {
#[serde(skip)]
Desktop(PathBuf, String, DesktopConfig),
#[serde(skip)]
Network(String, String),
Path(PathBuf),
Recents,
#[serde(skip)]
Search(PathBuf, String, bool, Instant),
Trash,
}
Expand Down