aethermap-gui 1.5.0

GUI client for aethermap input remapper
Documentation
use crate::gui::{AutoSwitchRule, AutoSwitchRulesView, Message, State};
use aethermap_common::ipc_client::IpcClient;
use aethermap_common::AutoSwitchRule as CommonAutoSwitchRule;
use aethermap_common::{Request, Response};
use iced::Command;

pub fn show(state: &mut State, device_id: String) -> Command<Message> {
    state.auto_switch_view = Some(AutoSwitchRulesView {
        device_id: device_id.clone(),
        rules: Vec::new(),
        editing_rule: None,
        new_app_id: String::new(),
        new_profile_name: String::new(),
        new_layer_id: String::new(),
    });
    let device_id_clone = device_id.clone();
    Command::perform(async move { device_id_clone }, |id| {
        Message::LoadAutoSwitchRules(id)
    })
}

pub fn close(state: &mut State) -> Command<Message> {
    state.auto_switch_view = None;
    Command::none()
}

pub fn load(state: &State) -> Command<Message> {
    let socket_path = state.socket_path.clone();
    Command::perform(
        async move {
            let client = IpcClient::with_socket_path(&socket_path);
            let request = Request::GetAutoSwitchRules;
            match client.send(&request).await {
                Ok(Response::AutoSwitchRules { rules }) => Ok(rules
                    .into_iter()
                    .map(|r| AutoSwitchRule {
                        app_id: r.app_id,
                        profile_name: r.profile_name,
                        device_id: r.device_id,
                        layer_id: r.layer_id,
                    })
                    .collect()),
                Ok(Response::Error(msg)) => Err(msg),
                Err(e) => Err(format!("IPC error: {}", e)),
                _ => Err("Unexpected response".to_string()),
            }
        },
        Message::AutoSwitchRulesLoaded,
    )
}

pub fn loaded(state: &mut State, rules: Vec<AutoSwitchRule>) -> Command<Message> {
    if let Some(view) = state.auto_switch_view.as_mut() {
        view.rules = rules;
    }
    Command::none()
}

pub fn load_error(state: &mut State, error: String) -> Command<Message> {
    state.add_notification(
        &format!("Failed to load auto-switch rules: {}", error),
        true,
    );
    Command::none()
}

pub fn edit(state: &mut State, index: usize) -> Command<Message> {
    if let Some(view) = &state.auto_switch_view {
        if let Some(rule) = view.rules.get(index) {
            state.auto_switch_view = Some(AutoSwitchRulesView {
                device_id: view.device_id.clone(),
                rules: view.rules.clone(),
                editing_rule: Some(index),
                new_app_id: rule.app_id.clone(),
                new_profile_name: rule.profile_name.clone(),
                new_layer_id: rule.layer_id.map(|id| id.to_string()).unwrap_or_default(),
            });
        }
    }
    Command::none()
}

pub fn app_id_changed(state: &mut State, value: String) -> Command<Message> {
    if let Some(view) = state.auto_switch_view.as_mut() {
        view.new_app_id = value;
    }
    Command::none()
}

pub fn profile_name_changed(state: &mut State, value: String) -> Command<Message> {
    if let Some(view) = state.auto_switch_view.as_mut() {
        view.new_profile_name = value;
    }
    Command::none()
}

pub fn layer_id_changed(state: &mut State, value: String) -> Command<Message> {
    if let Some(view) = state.auto_switch_view.as_mut() {
        view.new_layer_id = value;
    }
    Command::none()
}

pub fn use_current_app(state: &mut State) -> Command<Message> {
    if let Some(ref focus) = state.current_focus {
        if let Some(view) = state.auto_switch_view.as_mut() {
            view.new_app_id = focus.clone();
        }
    }
    Command::none()
}

pub fn save(state: &mut State) -> Command<Message> {
    if let Some(mut view) = state.auto_switch_view.clone() {
        let rule = AutoSwitchRule {
            app_id: view.new_app_id.clone(),
            profile_name: view.new_profile_name.clone(),
            device_id: Some(view.device_id.clone()),
            layer_id: view.new_layer_id.parse().ok(),
        };

        if let Some(editing) = view.editing_rule {
            if editing < view.rules.len() {
                view.rules[editing] = rule.clone();
            }
        } else {
            view.rules.push(rule.clone());
        }

        view.editing_rule = None;
        view.new_app_id = String::new();
        view.new_profile_name = String::new();
        view.new_layer_id = String::new();

        let rules = view.rules.clone();
        let socket_path = state.socket_path.clone();

        state.auto_switch_view = Some(view);

        Command::perform(
            async move {
                let common_rules: Vec<CommonAutoSwitchRule> = rules
                    .into_iter()
                    .map(|r| CommonAutoSwitchRule {
                        app_id: r.app_id,
                        profile_name: r.profile_name,
                        device_id: r.device_id,
                        layer_id: r.layer_id,
                    })
                    .collect();

                let client = IpcClient::with_socket_path(socket_path);
                let request = Request::SetAutoSwitchRules {
                    rules: common_rules,
                };
                match client.send(&request).await {
                    Ok(Response::AutoSwitchRulesAck) => Ok(()),
                    Ok(Response::Error(msg)) => Err(msg),
                    Err(e) => Err(format!("IPC error: {}", e)),
                    _ => Err("Unexpected response".to_string()),
                }
            },
            |result| match result {
                Ok(()) => Message::ShowNotification("Auto-switch rules saved".to_string(), false),
                Err(e) => Message::ShowNotification(format!("Failed to save rules: {}", e), true),
            },
        )
    } else {
        Command::none()
    }
}

pub fn delete(state: &mut State, index: usize) -> Command<Message> {
    if let Some(view) = state.auto_switch_view.clone() {
        if index < view.rules.len() {
            let mut rules = view.rules.clone();
            rules.remove(index);
            let socket_path = state.socket_path.clone();

            if let Some(v) = state.auto_switch_view.as_mut() {
                v.rules = rules.clone();
            }

            return Command::perform(
                async move {
                    let common_rules: Vec<CommonAutoSwitchRule> = rules
                        .into_iter()
                        .map(|r| CommonAutoSwitchRule {
                            app_id: r.app_id,
                            profile_name: r.profile_name,
                            device_id: r.device_id,
                            layer_id: r.layer_id,
                        })
                        .collect();

                    let client = IpcClient::with_socket_path(&socket_path);
                    let request = Request::SetAutoSwitchRules {
                        rules: common_rules,
                    };
                    match client.send(&request).await {
                        Ok(Response::AutoSwitchRulesAck) => Ok(()),
                        Ok(Response::Error(msg)) => Err(msg),
                        Err(e) => Err(format!("IPC error: {}", e)),
                        _ => Err("Unexpected response".to_string()),
                    }
                },
                |result| match result {
                    Ok(()) => Message::ShowNotification("Rule deleted".to_string(), false),
                    Err(e) => {
                        Message::ShowNotification(format!("Failed to delete rule: {}", e), true)
                    }
                },
            );
        }
    }
    Command::none()
}