Skip to content

Commit

Permalink
Move InputDialog over to the newer screen result approach
Browse files Browse the repository at this point in the history
See #9.
  • Loading branch information
davep committed May 2, 2023
1 parent e7b6e1e commit f51e52e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 69 deletions.
3 changes: 2 additions & 1 deletion frogmouth/dialogs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
from .error import ErrorDialog
from .help_dialog import HelpDialog
from .information import InformationDialog
from .input_dialog import InputDialog
from .input_dialog import InputDialog, InputDialogResult
from .yes_no_dialog import YesNoDialog

__all__ = [
"ErrorDialog",
"InformationDialog",
"InputDialog",
"InputDialogResult",
"HelpDialog",
"YesNoDialog",
]
50 changes: 14 additions & 36 deletions frogmouth/dialogs/input_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,27 @@

from __future__ import annotations

from typing import Any
from typing import NamedTuple

from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical
from textual.message import Message
from textual.screen import ModalScreen
from textual.widget import Widget
from textual.widgets import Button, Input, Label


class InputDialog(ModalScreen[None]):
class InputDialogResult(NamedTuple):
"""The result of input with an `InputDialog`."""

dialog_id: str | None
"""The ID of the dialog returning the result."""

value: str
"""The input value."""


class InputDialog(ModalScreen[InputDialogResult]):
"""A modal dialog for getting a single input from the user."""

DEFAULT_CSS = """
Expand Down Expand Up @@ -59,12 +68,11 @@ class InputDialog(ModalScreen[None]):
]
"""Bindings for the dialog."""

def __init__( # pylint:disable=redefined-builtin,too-many-arguments
def __init__( # pylint:disable=redefined-builtin
self,
requester: Widget,
prompt: str,
initial: str | None = None,
cargo: Any = None,
id: str | None = None,
) -> None:
"""Initialise the input dialog.
Expand All @@ -83,8 +91,6 @@ def __init__( # pylint:disable=redefined-builtin,too-many-arguments
"""The prompt to display for the input."""
self._initial = initial
"""The initial value to use for the input."""
self._cargo = cargo
"""Any cargo data for the input dialog."""

def compose(self) -> ComposeResult:
"""Compose the child widgets."""
Expand All @@ -100,33 +106,6 @@ def on_mount(self) -> None:
"""Set up the dialog once the DOM is ready."""
self.query_one(Input).focus()

class Result(Message):
"""The input dialog result message."""

def __init__(
self, sender_id: str | None, value: str, cargo: Any = None
) -> None:
"""Initialise the result message.
Args:
sender_id: The ID of the dialog sending the message.
value: The value to attach as the result.
cargo: Any cargo data for the result.
"""
super().__init__()
self.sender_id: str | None = sender_id
"""The ID of the sending dialog."""
self.value: str = value
"""The value of the result."""
self.cargo: Any = cargo
"""Cargo data for the result."""

def _return_input(self) -> None:
"""Return the input value from the dialog."""
self._requester.post_message(
self.Result(self.id, self.query_one(Input).value, self._cargo)
)

def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle one of the dialog's buttons been pressed.
Expand All @@ -136,8 +115,7 @@ def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id == "cancel":
self.app.pop_screen()
elif event.button.id == "ok" and self.query_one(Input).value.strip():
self._return_input()
self.app.pop_screen()
self.dismiss(InputDialogResult(self.id, self.query_one(Input).value))

def on_input_submitted(self) -> None:
"""Do default processing when the user hits enter in the input."""
Expand Down
35 changes: 19 additions & 16 deletions frogmouth/screens/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from functools import partial
from pathlib import Path
from typing import Awaitable, Callable
from webbrowser import open as open_url
Expand All @@ -16,7 +17,13 @@

from .. import __version__
from ..data import load_config, load_history, save_config, save_history
from ..dialogs import ErrorDialog, HelpDialog, InformationDialog, InputDialog
from ..dialogs import (
ErrorDialog,
HelpDialog,
InformationDialog,
InputDialog,
InputDialogResult,
)
from ..utility import (
build_raw_bitbucket_url,
build_raw_github_url,
Expand Down Expand Up @@ -471,6 +478,15 @@ def action_about(self) -> None:
)
)

def add_bookmark(self, location: Path | URL, bookmark: InputDialogResult) -> None:
"""Handle adding the bookmark.
Args:
location: The location to bookmark.
bookmark: The bookmark to add.
"""
self.query_one(Navigation).bookmarks.add_bookmark(bookmark.value, location)

def action_bookmark_this(self) -> None:
"""Add a bookmark for the currently-viewed file."""

Expand All @@ -493,23 +509,10 @@ def action_bookmark_this(self) -> None:

# Give the user a chance to edit the title.
self.app.push_screen(
InputDialog(self, "Bookmark title:", title, location, id="add_bookmark")
InputDialog(self, "Bookmark title:", title),
partial(self.add_bookmark, location),
)

def on_input_dialog_result(self, event: InputDialog.Result) -> None:
"""Handle a result coming back from an input dialog.
Args:
event: The input dialog result event.
"""
# Handle the correct source dialog.
if event.sender_id == "add_bookmark":
# The cargo value for the result should be the location, which
# should be a path or a URL.
assert isinstance(event.cargo, (Path, URL))
# Save the bookmark.
self.query_one(Navigation).bookmarks.add_bookmark(event.value, event.cargo)

def action_toggle_theme(self) -> None:
"""Toggle the light/dark mode theme."""
config = load_config()
Expand Down
32 changes: 16 additions & 16 deletions frogmouth/widgets/navigation_panes/bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from functools import partial
from pathlib import Path

from httpx import URL
Expand All @@ -13,7 +14,7 @@
from textual.widgets.option_list import Option

from ...data import Bookmark, load_bookmarks, save_bookmarks
from ...dialogs import InputDialog, YesNoDialog
from ...dialogs import InputDialog, InputDialogResult, YesNoDialog
from .navigation_pane import NavigationPane


Expand Down Expand Up @@ -146,6 +147,18 @@ def on_yes_no_dialog_positive_reply(self, event: YesNoDialog.PositiveReply) -> N
del self._bookmarks[bookmarks.highlighted]
self._bookmarks_updated()

def rename_bookmark(self, bookmark: int, new_name: InputDialogResult) -> None:
"""Rename the current bookmark.
Args:
bookmark: The location of the bookmark to rename.
new_name: The input dialog result that is the new name.
"""
self._bookmarks[bookmark] = Bookmark(
new_name.value, self._bookmarks[bookmark].location
)
self._bookmarks_updated()

def action_rename(self) -> None:
"""Rename the highlighted bookmark."""
if (bookmark := self.query_one(OptionList).highlighted) is not None:
Expand All @@ -154,19 +167,6 @@ def action_rename(self) -> None:
self,
"Bookmark title:",
self._bookmarks[bookmark].title,
bookmark,
id="edit_title",
)
),
partial(self.rename_bookmark, bookmark),
)

def on_input_dialog_result(self, event: InputDialog.Result) -> None:
"""Handle an input dialog result being passed to us."""
if event.sender_id == "edit_title":
# The cargo value for the result should be the index of the
# bookmark we're changing.
assert isinstance(event.cargo, int)
# Everything looks good, update the bookmarks.
self._bookmarks[event.cargo] = Bookmark(
event.value, self._bookmarks[event.cargo].location
)
self._bookmarks_updated()

0 comments on commit f51e52e

Please sign in to comment.