feat: add support for jumping to specific item
This also cleans up some type checker issues
This commit is contained in:
@@ -9,13 +9,15 @@ Here's an example usage:
|
||||
|
||||
import pathlib
|
||||
import random
|
||||
from typing import cast, override
|
||||
from typing import ClassVar, cast, final, override
|
||||
|
||||
import typed_argparse as tap
|
||||
from textual import work
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.binding import BindingType
|
||||
from textual.widgets import Footer, Header, Label
|
||||
from textual.containers import Grid
|
||||
from textual.screen import ModalScreen
|
||||
from textual.widgets import Footer, Header, Input, Label
|
||||
from textual.worker import Worker, WorkerState
|
||||
|
||||
from random_file_picker.core import IMG_EXTENSIONS, collect_files, move_file_to_move_folder, trash_file, upload_file
|
||||
@@ -38,12 +40,50 @@ class Args(tap.TypedArgs):
|
||||
blacklist: list[str] | None = tap.arg("--blacklist", nargs="*", help="List of glob patterns to blacklist files")
|
||||
whitelist: list[str] | None = tap.arg("--whitelist", nargs="*", help="List of glob patterns to whitelist files")
|
||||
|
||||
@final
|
||||
class JumpModal(ModalScreen[int | None]):
|
||||
"""Modal screen to prompt the user for an item index to skip to."""
|
||||
|
||||
# css in the terminal before gta6
|
||||
DEFAULT_CSS = """
|
||||
JumpModal {
|
||||
align: center middle;
|
||||
}
|
||||
#dialog {
|
||||
grid-size: 1;
|
||||
padding: 1 2;
|
||||
width: 40;
|
||||
height: 11;
|
||||
border: thick $background 80%;
|
||||
background: $surface;
|
||||
}
|
||||
"""
|
||||
|
||||
@override
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Grid(
|
||||
Label("Enter item index to jump to:"),
|
||||
Input(placeholder="e.g. 5", id="index-input", type="integer"),
|
||||
id="dialog",
|
||||
)
|
||||
|
||||
def on_input_submitted(self, event: Input.Submitted) -> None:
|
||||
"""Handle the submission of the input field, dismissing the modal with the entered index."""
|
||||
val = event.value.strip()
|
||||
if val.isdigit():
|
||||
_ = self.dismiss(int(val))
|
||||
return
|
||||
_ = self.dismiss(None)
|
||||
|
||||
|
||||
class MenuApp(App[None]):
|
||||
# This defines the keys shown in the footer
|
||||
BINDINGS: list[BindingType] = [
|
||||
BINDINGS: ClassVar[list[BindingType]] = [
|
||||
("left", "prev_file", "Previous File"),
|
||||
("right", "next_file", "Next File"),
|
||||
("r", "reopen_file", "Reopen"),
|
||||
("colon", "jump_to_item", "Jump to Item"),
|
||||
("g", "jump_to_item", "Jump to Item"),
|
||||
("u", "upload", "Upload"),
|
||||
("d", "delete", "Delete"),
|
||||
("m", "move_to_folder", "Move File"),
|
||||
@@ -53,6 +93,7 @@ class MenuApp(App[None]):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
directory: str = ".",
|
||||
file_limit: int = 10,
|
||||
recurse: bool = False,
|
||||
@@ -60,6 +101,7 @@ class MenuApp(App[None]):
|
||||
whitelist: list[str] | None = None,
|
||||
use_geeqie: bool = False,
|
||||
use_trash: bool = True,
|
||||
no_random: bool = False,
|
||||
):
|
||||
super().__init__()
|
||||
self.directory: pathlib.Path = pathlib.Path(directory)
|
||||
@@ -69,6 +111,7 @@ class MenuApp(App[None]):
|
||||
self.whitelist_patterns: list[str] = whitelist or []
|
||||
self.use_geeqie: bool = use_geeqie
|
||||
self.use_trash: bool = use_trash
|
||||
self.no_random: bool = no_random
|
||||
self.usable_files: list[pathlib.Path] = []
|
||||
self.current_index: int = 0
|
||||
self.current_file: pathlib.Path | None = None
|
||||
@@ -82,6 +125,7 @@ class MenuApp(App[None]):
|
||||
yield Footer()
|
||||
|
||||
def on_mount(self) -> None:
|
||||
"""On application mount, start gathering files in the background."""
|
||||
self.start_gathering_files()
|
||||
|
||||
@override
|
||||
@@ -307,6 +351,22 @@ class MenuApp(App[None]):
|
||||
self.open_file()
|
||||
self.query_one("#status", Label).update("🔄 Reopened file")
|
||||
|
||||
def action_jump_to_item(self) -> None:
|
||||
"""Prompt for item number and jump to it."""
|
||||
if not self.usable_files:
|
||||
return
|
||||
|
||||
def check_jump(target_1based: int | None) -> None:
|
||||
if target_1based is None:
|
||||
return
|
||||
if 1 <= target_1based <= len(self.usable_files):
|
||||
self.current_index = target_1based - 1
|
||||
self.display_current_file()
|
||||
else:
|
||||
self.query_one("#status", Label).update(f"❌ Index out of range (1 - {len(self.usable_files)})")
|
||||
|
||||
_ = self.push_screen(JumpModal(), check_jump)
|
||||
|
||||
|
||||
def main_with_tap(args: Args) -> None:
|
||||
if args.use_geeqie and not GEEQIE_AVAILABLE:
|
||||
|
||||
Reference in New Issue
Block a user