foxygit / ytmdl Log in
commits tags

/src/ytmdl/screens.py · 3.42 KB

raw
from __future__ import annotations

from pathlib import Path
from typing import Iterable

from textual.command import CommandPalette
from textual.containers import Horizontal, Vertical
from textual.reactive import var
from textual.screen import ModalScreen
from textual.widgets import Button, DirectoryTree, Label


class NerdCommandPalette(CommandPalette):
    icon: var[str] = var(" ")  # nf-fa-search


class DirsOnlyDirectoryTree(DirectoryTree):
    ICON_NODE = " "  # nf-fa-folder
    ICON_NODE_EXPANDED = " "  # nf-fa-folder_open

    def filter_paths(self, paths: Iterable[Path]) -> Iterable[Path]:
        return [p for p in paths if p.is_dir() and not p.name.startswith(".")]


class DirectoryPickerScreen(ModalScreen[Path | None]):
    CSS = """
    DirectoryPickerScreen {
        align: center middle;
    }

    #picker-dialog {
        width: 80%;
        height: 80%;
        border: round $primary;
        background: $surface;
        padding: 1 2;
    }

    #picker-title {
        height: auto;
        text-style: bold;
    }

    #picker-current {
        height: auto;
        color: $text-muted;
        margin-bottom: 1;
    }

    DirsOnlyDirectoryTree {
        height: 1fr;
        border: round $panel;
    }

    #picker-buttons {
        height: auto;
        margin-top: 1;
        align: right middle;
    }

    #picker-buttons Button {
        margin-left: 1;
    }

    #up-btn {
        dock: left;
        margin-left: 0;
    }
    """

    BINDINGS = [
        ("escape", "cancel", "Cancel"),
        ("backspace", "go_up", "Up"),
    ]

    def __init__(self, start_path: Path) -> None:
        super().__init__()
        path = start_path
        while not path.is_dir():
            if path.parent == path:
                path = Path.home()
                break
            path = path.parent
        self.start_path = path
        self.selected_path = path

    def compose(self):
        yield Vertical(
            Label("Choose a folder to save downloads to", id="picker-title"),
            Label(str(self.selected_path), id="picker-current"),
            DirsOnlyDirectoryTree(self.start_path, id="picker-tree"),
            Horizontal(
                Button("Up", id="up-btn"),
                Button("Cancel", id="cancel-btn"),
                Button("Select", id="select-btn", variant="primary"),
                id="picker-buttons",
            ),
            id="picker-dialog",
        )

    def on_mount(self) -> None:
        self.query_one(DirsOnlyDirectoryTree).focus()

    def on_directory_tree_directory_selected(
        self, event: DirectoryTree.DirectorySelected
    ) -> None:
        self.selected_path = event.path
        self.query_one("#picker-current", Label).update(str(self.selected_path))

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "select-btn":
            self.dismiss(self.selected_path)
        elif event.button.id == "cancel-btn":
            self.dismiss(None)
        elif event.button.id == "up-btn":
            self.action_go_up()

    def action_cancel(self) -> None:
        self.dismiss(None)

    def action_go_up(self) -> None:
        tree = self.query_one(DirsOnlyDirectoryTree)
        current_root = Path(tree.path)
        parent = current_root.parent
        if parent == current_root:
            return
        tree.path = parent
        self.selected_path = parent
        self.query_one("#picker-current", Label).update(str(parent))