drifter 0.1.13

A TUI-based S3 multipart uploader featuring resumable transfers and ClamAV integration.
Documentation
use crate::app::settings::SettingsCategory;
use crate::app::state::{App, AppFocus, InputMode};

#[derive(Clone, Copy)]
pub struct KeyHint {
    pub key: Option<&'static str>,
    pub action: &'static str,
}

fn key_action(key: &'static str, action: &'static str) -> KeyHint {
    KeyHint {
        key: Some(key),
        action,
    }
}

fn text(action: &'static str) -> KeyHint {
    KeyHint { key: None, action }
}

fn settings_category_hints(category: SettingsCategory) -> Vec<KeyHint> {
    match category {
        SettingsCategory::S3 => vec![
            key_action("Tab/→", "Fields"),
            key_action("", "Rail"),
            key_action("↑/↓", "Category"),
            key_action("[]", "Cycle S3"),
            key_action("n/x", "New/Del S3"),
            key_action("s", "Save"),
            key_action("t", "Test"),
        ],
        SettingsCategory::Scanner => vec![
            key_action("Tab/→", "Fields"),
            key_action("", "Rail"),
            key_action("↑/↓", "Category"),
            key_action("s", "Save"),
            key_action("t", "Test"),
        ],
        SettingsCategory::Performance | SettingsCategory::General => vec![
            key_action("Tab/→", "Fields"),
            key_action("", "Rail"),
            key_action("↑/↓", "Category"),
            key_action("s", "Save"),
        ],
    }
}

fn settings_field_hints(category: SettingsCategory) -> Vec<KeyHint> {
    match category {
        SettingsCategory::S3 => vec![
            key_action("", "Category"),
            key_action("Enter", "Edit"),
            key_action("[]", "Cycle S3"),
            key_action("n/x", "New/Del S3"),
            key_action("s", "Save"),
            key_action("t", "Test"),
        ],
        SettingsCategory::Scanner => vec![
            key_action("", "Category"),
            key_action("Enter", "Edit"),
            key_action("s", "Save"),
            key_action("t", "Test"),
        ],
        SettingsCategory::Performance => vec![
            key_action("", "Category"),
            key_action("Enter", "Edit"),
            key_action("s", "Save"),
        ],
        SettingsCategory::General => vec![
            key_action("", "Category"),
            key_action("Enter", "Edit/Open"),
            key_action("s", "Save"),
        ],
    }
}

pub fn footer_hints(app: &App) -> Vec<KeyHint> {
    match app.input_mode {
        InputMode::LogSearch => vec![key_action("Enter", "Search"), key_action("Esc", "Cancel")],
        InputMode::QueueSearch | InputMode::HistorySearch => {
            vec![text("Type to filter"), key_action("Enter/Esc", "Done")]
        }
        InputMode::Filter => vec![
            text("Type to filter"),
            key_action("↑/↓", "Select"),
            key_action("Enter", "Open"),
            key_action("Esc", "Back"),
        ],
        InputMode::Browsing => {
            let mut hints = vec![
                key_action("←/→", "Navigate"),
                key_action("↑/↓", "Select"),
                key_action("/", "Filter"),
                key_action("t", "Tree"),
                key_action("Space", "Select"),
                key_action("Esc/q", "Exit"),
            ];
            if matches!(
                app.transfer_direction,
                crate::core::transfer::TransferDirection::LocalToS3
            ) {
                hints.push(key_action("s", "Stage"));
            } else {
                hints.push(key_action("s", "Upload Off"));
            }
            hints.push(key_action("v", "Mode"));
            hints
        }
        InputMode::RemoteBrowsing => {
            let mut hints = vec![
                key_action("←/→", "Navigate"),
                key_action("↑/↓", "Select"),
                key_action("e", "Select Ep"),
                key_action("r", "Refresh"),
                key_action("d", "Download"),
                key_action("x", "Delete"),
                key_action("n", "New Folder"),
                key_action("Esc/q", "Exit"),
            ];
            if matches!(
                app.transfer_direction,
                crate::core::transfer::TransferDirection::S3ToLocal
                    | crate::core::transfer::TransferDirection::S3ToS3
            ) {
                hints.push(key_action("s", "Queue"));
            }
            if app.focus == AppFocus::Remote
                || (app.focus == AppFocus::Browser
                    && matches!(
                        app.transfer_direction,
                        crate::core::transfer::TransferDirection::S3ToS3
                    ))
            {
                hints.push(key_action("Space", "Select"));
                hints.push(key_action("c", "Clear Sel"));
            }
            hints.push(key_action("v", "Mode"));
            hints
        }
        InputMode::RemoteFolderCreate => {
            vec![key_action("Enter", "Create"), key_action("Esc", "Cancel")]
        }
        InputMode::EndpointSelect => vec![
            key_action("↑/↓", "Select"),
            key_action("Enter", "Apply"),
            key_action("Esc", "Cancel"),
        ],
        InputMode::Confirmation => vec![
            key_action("Enter/y", "Confirm"),
            key_action("Esc/n", "Cancel"),
        ],
        InputMode::LayoutAdjust => vec![
            key_action("1-3", "Select Panel"),
            key_action("+/-", "Adjust"),
            key_action("r/R", "Reset"),
            key_action("s", "Save"),
            key_action("Esc/q", "Cancel"),
        ],
        InputMode::Normal => {
            let mut hints = match app.focus {
                AppFocus::Logs => vec![key_action("q", "Back")],
                AppFocus::Rail => vec![
                    key_action("Tab/→", "Content"),
                    key_action("↑/↓", "Switch Tab"),
                ],
                AppFocus::Browser => {
                    let mut hints = if matches!(
                        app.transfer_direction,
                        crate::core::transfer::TransferDirection::S3ToS3
                    ) {
                        vec![
                            key_action("e", "Select Ep"),
                            key_action("a", "Browse"),
                            key_action("r", "Refresh"),
                            key_action("x", "Delete"),
                            key_action("Space", "Select"),
                            key_action("c", "Clear Sel"),
                        ]
                    } else {
                        vec![key_action("↑/↓", "Select"), key_action("a", "Browse")]
                    };
                    hints.push(key_action("v", "Mode"));
                    hints
                }
                AppFocus::Queue => vec![
                    key_action("↑/↓", "Select"),
                    key_action("p", "Pause/Resume"),
                    key_action("+/-", "Priority"),
                    key_action("Enter", "Details"),
                    key_action("c", "Clear Done"),
                    key_action("r", "Retry"),
                    key_action("←/→", "Navigate"),
                    key_action("d", "Cancel"),
                ],
                AppFocus::History => vec![key_action("", "Queue")],
                AppFocus::Remote => {
                    let mut hints = vec![
                        key_action("e", "Select Ep"),
                        key_action("a", "Browse"),
                        key_action("r", "Refresh"),
                        key_action("d", "Download"),
                        key_action("x", "Delete"),
                    ];
                    if matches!(
                        app.transfer_direction,
                        crate::core::transfer::TransferDirection::S3ToLocal
                            | crate::core::transfer::TransferDirection::S3ToS3
                    ) {
                        hints.push(key_action("s", "Queue"));
                    }
                    if matches!(
                        app.transfer_direction,
                        crate::core::transfer::TransferDirection::LocalToS3
                            | crate::core::transfer::TransferDirection::S3ToLocal
                            | crate::core::transfer::TransferDirection::S3ToS3
                    ) {
                        hints.push(key_action("Space", "Select"));
                        hints.push(key_action("c", "Clear Sel"));
                    }
                    hints.push(key_action("v", "Mode"));
                    hints
                }
                AppFocus::Quarantine => vec![
                    key_action("", "Rail"),
                    key_action("d", "Clear"),
                    key_action("R", "Refresh"),
                ],
                AppFocus::SettingsCategory => {
                    let category = app.settings.active_category;
                    settings_category_hints(category)
                }
                AppFocus::SettingsFields => {
                    let category = app.settings.active_category;
                    settings_field_hints(category)
                }
            };

            hints.push(key_action("Tab", "Navigate"));
            if app.focus != AppFocus::Logs {
                hints.push(key_action("q", "Quit"));
            }
            hints
        }
    }
}