feat: add toggle for layer shell/window api

This commit is contained in:
ByteAtATime 2025-11-29 16:43:31 -08:00
parent 1c058b46d3
commit c11337923d
No known key found for this signature in database
6 changed files with 159 additions and 34 deletions

View file

@ -72,8 +72,12 @@ fn dev_boot() -> (State, iced::Task<Message>) {
fn daemon_view<'a>(state: &'a State, window: window::Id) -> iced::Element<'a, Message> {
if state.settings_window_id == Some(window) {
return screens::settings::settings_view(&state.extensions, &state.preferences)
.map(Message::Settings);
return screens::settings::settings_view(
&state.extensions,
&state.preferences,
&state.flare_settings,
)
.map(Message::Settings);
}
view(state)
}
@ -229,20 +233,33 @@ fn run_daemon() -> Result<(), Box<dyn std::error::Error>> {
eprintln!("Failed to register deep links: {}", e);
}
let result = iced_layershell::daemon(boot, namespace, update, daemon_view)
.subscription(subscription)
.title(|_state, _window| Some(String::from("Flare")))
.font(include_bytes!("./assets/Inter.ttf").as_slice())
.font(include_bytes!("./assets/icons.ttf").as_slice())
.default_font(iced::Font::DEFAULT)
.layer_settings(LayerShellSettings {
start_mode: StartMode::Background,
keyboard_interactivity: KeyboardInteractivity::Exclusive,
layer: Layer::Overlay,
..Default::default()
})
.run()
.map_err(|e| e.to_string());
let flare_settings = preferences::FlareSettings::load();
let result = if flare_settings.use_layer_shell {
iced_layershell::daemon(boot, namespace, update, daemon_view)
.subscription(subscription)
.title(|_state, _window| Some(String::from("Flare")))
.font(include_bytes!("./assets/Inter.ttf").as_slice())
.font(include_bytes!("./assets/icons.ttf").as_slice())
.default_font(iced::Font::DEFAULT)
.layer_settings(LayerShellSettings {
start_mode: StartMode::Background,
keyboard_interactivity: KeyboardInteractivity::Exclusive,
layer: Layer::Overlay,
..Default::default()
})
.run()
.map_err(|e| e.to_string())
} else {
iced::daemon(boot, update, daemon_view)
.subscription(subscription)
.title("Flare")
.font(include_bytes!("./assets/Inter.ttf").as_slice())
.font(include_bytes!("./assets/icons.ttf").as_slice())
.default_font(iced::Font::DEFAULT)
.run()
.map_err(|e| e.to_string())
};
ipc::cleanup();
result?;

View file

@ -8,6 +8,45 @@ use crate::extensions::Extension;
pub type ExtensionPreferences = HashMap<String, Value>;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct FlareSettings {
#[serde(default = "default_use_layer_shell")]
pub use_layer_shell: bool,
}
fn default_use_layer_shell() -> bool {
true
}
impl FlareSettings {
pub fn load() -> Self {
let path = get_flare_settings_path();
fs::read_to_string(&path)
.ok()
.and_then(|content| serde_json::from_str(&content).ok())
.unwrap_or_default()
}
pub fn save(&self) -> Result<(), String> {
let path = get_flare_settings_path();
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).map_err(|e| e.to_string())?;
}
let content = serde_json::to_string_pretty(self).map_err(|e| e.to_string())?;
fs::write(path, content).map_err(|e| e.to_string())
}
}
fn get_flare_settings_path() -> PathBuf {
if let Some(config_dir) = dirs::config_dir() {
return config_dir.join("flare").join("settings.json");
}
if let Some(home_dir) = dirs::home_dir() {
return home_dir.join(".flare").join("settings.json");
}
PathBuf::from(".flare").join("settings.json")
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PreferenceStore {
extensions: HashMap<String, ExtensionPreferences>,

View file

@ -11,4 +11,7 @@ pub enum SettingsMessage {
key: String,
value: Value,
},
FlareSettingChanged {
use_layer_shell: bool,
},
}

View file

@ -1,22 +1,68 @@
use iced::Element;
use iced::widget::{checkbox, column, pick_list, row, scrollable, text, text_input};
use iced::widget::{checkbox, column, pick_list, radio, row, scrollable, text, text_input};
use serde_json::Value;
use crate::extensions::{Extension, Preference, PreferenceType};
use crate::preferences::PreferenceStore;
use crate::preferences::{FlareSettings, PreferenceStore};
use super::SettingsMessage;
pub fn settings_view<'a>(
extensions: &'a [Extension],
preferences: &'a PreferenceStore,
flare_settings: &'a FlareSettings,
) -> Element<'a, SettingsMessage> {
let mut content = column![].spacing(10).padding(20);
let mut content = column![].spacing(20).padding(20);
content = content.push(text("Settings").size(24));
content = content.push(render_flare_settings(flare_settings));
content = content.push(render_extension_settings(extensions, preferences));
scrollable(content).into()
}
fn render_flare_settings(settings: &FlareSettings) -> Element<'_, SettingsMessage> {
let mut content = column![].spacing(10);
content = content.push(text("Flare Settings").size(18));
let layer_shell_row = row![
text("Window Mode").width(150),
radio(
"Layer Shell (Wayland)",
true,
Some(settings.use_layer_shell),
|v| SettingsMessage::FlareSettingChanged { use_layer_shell: v }
),
radio(
"Regular Window",
false,
Some(settings.use_layer_shell),
|v| SettingsMessage::FlareSettingChanged { use_layer_shell: v }
),
]
.spacing(10)
.align_y(iced::Alignment::Center);
content = content.push(layer_shell_row);
content =
content.push(text("After changing this setting, please restart the application.").size(12));
content.into()
}
fn render_extension_settings<'a>(
extensions: &'a [Extension],
preferences: &'a PreferenceStore,
) -> Element<'a, SettingsMessage> {
let mut content = column![].spacing(10);
content = content.push(text("Extension Settings").size(18));
for ext in extensions {
content = content.push(text(format!("Extension: {}", ext.manifest.title)).size(18));
content = content.push(text(format!("Extension: {}", ext.manifest.title)).size(16));
if let Some(prefs) = &ext.manifest.preferences {
for pref in prefs {
@ -32,7 +78,7 @@ pub fn settings_view<'a>(
for cmd in &ext.manifest.commands {
if let Some(prefs) = &cmd.preferences {
if !prefs.is_empty() {
content = content.push(text(format!("Command: {}", cmd.title)).size(16));
content = content.push(text(format!("Command: {}", cmd.title)).size(14));
for pref in prefs {
content = content.push(render_preference(
&ext.manifest.name,
@ -46,7 +92,7 @@ pub fn settings_view<'a>(
}
}
scrollable(content).into()
content.into()
}
fn render_preference<'a>(

View file

@ -9,7 +9,7 @@ use crate::components::action_panel;
use crate::components::actions::ActionPanelItem;
use crate::extensions;
use crate::frecency::FrecencyStore;
use crate::preferences::PreferenceStore;
use crate::preferences::{FlareSettings, PreferenceStore};
use crate::screens::{Screen, Shell};
use crate::theme::Theme;
use crate::transport::{SidecarReader, SidecarWriter};
@ -19,6 +19,7 @@ pub struct State {
pub extensions: Vec<extensions::Extension>,
pub apps: Vec<apps::AppEntry>,
pub preferences: PreferenceStore,
pub flare_settings: FlareSettings,
pub frecency: FrecencyStore,
pub theme: Theme,
pub search_text: String,
@ -51,6 +52,7 @@ impl State {
let commands = extensions::get_launchable_commands(&extensions);
let apps = apps::scan_applications();
let preferences = PreferenceStore::load();
let flare_settings = FlareSettings::load();
let frecency = FrecencyStore::new(get_frecency_path());
let theme = Theme::default();
@ -67,6 +69,7 @@ impl State {
extensions,
apps,
preferences,
flare_settings,
frecency,
theme,
search_text,

View file

@ -51,18 +51,29 @@ pub fn update(state: &mut State, message: Message) -> Task<Message> {
} else {
#[cfg(target_os = "linux")]
{
let id = window::Id::unique();
state.window_id = Some(id);
return Task::done(Message::NewLayerShell {
settings: NewLayerShellSettings {
size: Some((774, 474)),
anchor: Anchor::empty(),
layer: Layer::Overlay,
keyboard_interactivity: KeyboardInteractivity::Exclusive,
if state.flare_settings.use_layer_shell {
let id = window::Id::unique();
state.window_id = Some(id);
return Task::done(Message::NewLayerShell {
settings: NewLayerShellSettings {
size: Some((774, 474)),
anchor: Anchor::empty(),
layer: Layer::Overlay,
keyboard_interactivity: KeyboardInteractivity::Exclusive,
..Default::default()
},
id,
});
} else {
let (id, open) = window::open(window::Settings {
decorations: false,
level: window::Level::AlwaysOnTop,
resizable: false,
size: iced::Size::new(774.0, 474.0),
..Default::default()
},
id,
});
});
return open.map(move |_| Message::WindowOpened(id));
}
}
#[cfg(not(target_os = "linux"))]
{
@ -254,6 +265,12 @@ pub fn update(state: &mut State, message: Message) -> Task<Message> {
eprintln!("Failed to save preferences: {}", e);
}
}
SettingsMessage::FlareSettingChanged { use_layer_shell } => {
state.flare_settings.use_layer_shell = use_layer_shell;
if let Err(e) = state.flare_settings.save() {
eprintln!("Failed to save Flare settings: {}", e);
}
}
}
}
Message::OpenUrl(url) => {