basic nav status counts

This commit is contained in:
Tim Bendt
2025-04-30 16:47:16 -04:00
parent 3a5cb7d5d3
commit 7a5b911414
14 changed files with 72 additions and 19 deletions

View File

@@ -13,7 +13,6 @@ def action_archive(app) -> None:
) )
if result.returncode == 0: if result.returncode == 0:
app.query_one("#main_content", Static).update(f"Message {app.current_message_id} archived.") app.query_one("#main_content", Static).update(f"Message {app.current_message_id} archived.")
app.show_status(f"Message {app.current_message_id} archived.")
action_next(app) # Automatically show the next message action_next(app) # Automatically show the next message
else: else:
app.query_one("#main_content", Static).update(f"Failed to archive message {app.current_message_id}.") app.query_one("#main_content", Static).update(f"Failed to archive message {app.current_message_id}.")

View File

@@ -23,13 +23,13 @@ def action_next(app) -> None:
import json import json
envelopes = json.loads(result.stdout) envelopes = json.loads(result.stdout)
ids = sorted(int(envelope['id']) for envelope in envelopes) ids = sorted(int(envelope['id']) for envelope in envelopes)
for envelope_id in ids: for index, envelope_id in enumerate(ids):
if envelope_id > app.current_message_id: if envelope_id > int(app.current_message_id):
app.current_message_id = envelope_id app.show_message(envelope_id)
app.show_message(app.current_message_id)
app.show_status(f"Showing next message: {app.current_message_id}")
return return
app.show_status("No newer messages found.", severity="warning") app.show_status("No newer messages found.", severity="warning")
app.show_message(envelopes[-1]['id']) # Automatically show the previous message
else: else:
app.show_status("Failed to fetch envelope list.", severity="error") app.show_status("Failed to fetch envelope list.", severity="error")
except Exception as e: except Exception as e:

View File

@@ -6,7 +6,6 @@ def action_open(app) -> None:
def check_id(message_id: str) -> bool: def check_id(message_id: str) -> bool:
try: try:
int(message_id) int(message_id)
app.show_status(f"Opening message {message_id}...")
app.current_message_id = message_id app.current_message_id = message_id
app.show_message(app.current_message_id) app.show_message(app.current_message_id)
except ValueError: except ValueError:

View File

@@ -14,10 +14,9 @@ def action_previous(app) -> None:
envelopes = json.loads(result.stdout) envelopes = json.loads(result.stdout)
ids = sorted((int(envelope['id']) for envelope in envelopes), reverse=True) ids = sorted((int(envelope['id']) for envelope in envelopes), reverse=True)
for envelope_id in ids: for envelope_id in ids:
if envelope_id < app.current_message_id: if envelope_id < int(app.current_message_id):
app.current_message_id = envelope_id app.current_message_id = envelope_id
app.show_message(app.current_message_id) app.show_message(app.current_message_id)
app.show_status(f"Showing previous message: {app.current_message_id}")
return return
app.show_status("No older messages found.", severity="warning") app.show_status("No older messages found.", severity="warning")
else: else:

View File

@@ -1,8 +1,10 @@
from textual.widgets import Static from textual.widgets import Static
from rich.markdown import Markdown
import subprocess import subprocess
def show_message(app, message_id: int) -> None: def show_message(app, message_id: int) -> None:
"""Fetch and display the email message by ID.""" """Fetch and display the email message by ID."""
app.current_message_id = message_id
app.query_one("#main_content", Static).loading = True app.query_one("#main_content", Static).loading = True
try: try:
result = subprocess.run( result = subprocess.run(
@@ -12,7 +14,6 @@ def show_message(app, message_id: int) -> None:
) )
if result.returncode == 0: if result.returncode == 0:
# Render the email content as Markdown # Render the email content as Markdown
from rich.markdown import Markdown
markdown_content = Markdown(result.stdout, justify=True) markdown_content = Markdown(result.stdout, justify=True)
app.query_one("#main_content", Static).loading = False app.query_one("#main_content", Static).loading = False
app.query_one("#main_content", Static).update(markdown_content) app.query_one("#main_content", Static).update(markdown_content)

View File

@@ -5,7 +5,8 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import logging import logging
from typing import Iterable from typing import Iterable
from textual import on from textual import on
from textual.app import App, ComposeResult, SystemCommand from textual.widget import Widget
from textual.app import App, ComposeResult, SystemCommand, RenderResult
from textual.logging import TextualHandler from textual.logging import TextualHandler
from textual.screen import Screen from textual.screen import Screen
from textual.widgets import Header, Footer, Static, Label, Input, Button from textual.widgets import Header, Footer, Static, Label, Input, Button
@@ -27,13 +28,29 @@ logging.basicConfig(
handlers=[TextualHandler()], handlers=[TextualHandler()],
) )
class Hello(Widget):
"""Display a greeting."""
def render(self) -> RenderResult:
return "Hello, [b]World[/b]!"
class StatusTitle(Static):
total_messages: Reactive[int] = Reactive(0)
current_message_index: Reactive[int] = Reactive(0)
current_message_id: Reactive[int] = Reactive(1)
def render(self) -> RenderResult:
return f"Inbox Message ID: {self.current_message_id} | [b]{self.current_message_index}[/b]/{self.total_messages}"
class EmailViewerApp(App): class EmailViewerApp(App):
"""A simple email viewer app using the Himalaya CLI.""" """A simple email viewer app using the Himalaya CLI."""
title = "Maildir GTD Reader" title = "Maildir GTD Reader"
CSS_PATH = "email_viewer.tcss" # Optional: For styling
current_message_id: Reactive[int] = Reactive(1) current_message_id: Reactive[int] = Reactive(1)
CSS_PATH = "email_viewer.tcss"
def get_system_commands(self, screen: Screen) -> Iterable[SystemCommand]: def get_system_commands(self, screen: Screen) -> Iterable[SystemCommand]:
yield from super().get_system_commands(screen) yield from super().get_system_commands(screen)
@@ -64,12 +81,43 @@ class EmailViewerApp(App):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
"""Create child widgets for the app.""" """Create child widgets for the app."""
yield Header(show_clock=True) yield Header(show_clock=True)
yield Footer(Label("[n] Next | [p] Previous | [d] Delete | [a] Archive | [o] Open | [q] Quit | [c] Create Task")) yield StatusTitle().data_bind(EmailViewerApp.current_message_id)
yield ScrollableContainer(Static(Label("Email Viewer App"), id="main_content")) yield ScrollableContainer(Static(Label("Loading Email Viewer App"), id="main_content"))
yield Footer()
def watch_current_message_id(self, message_id: int, old_message_id: int) -> None:
"""Called when the current message ID changes."""
if (message_id == old_message_id):
return
# self.notify("Current message ID changed", title="Status", severity="information")
logging.info(f"Current message ID changed to {message_id}")
try:
result = subprocess.run(
["himalaya", "envelope", "list", "-o", "json"],
capture_output=True,
text=True
)
if result.returncode == 0:
import json
envelopes = json.loads(result.stdout)
if envelopes:
status = self.query_one(StatusTitle)
status.total_messages = len(envelopes) # Get the first envelope's ID
status.current_message_index = next(
(index + 1 for index, envelope in enumerate(envelopes) if int(envelope['id']) == message_id),
0 # Default to 0 if no match is found
)
else:
self.query_one("#main_content", Static).update("Failed to fetch the most recent message ID.")
except Exception as e:
self.query_one("#main_content", Static).update(f"Error: {e}")
def on_mount(self) -> None: def on_mount(self) -> None:
"""Called when the app is mounted."""
self.alert_timer: Timer | None = None # Timer to throttle alerts self.alert_timer: Timer | None = None # Timer to throttle alerts
self.theme = "monokai"
# self.watch(self.query_one(StatusTitle), "current_message_id", update_progress)
# Fetch the ID of the most recent message using the Himalaya CLI # Fetch the ID of the most recent message using the Himalaya CLI
try: try:
result = subprocess.run( result = subprocess.run(
@@ -81,7 +129,7 @@ class EmailViewerApp(App):
import json import json
envelopes = json.loads(result.stdout) envelopes = json.loads(result.stdout)
if envelopes: if envelopes:
self.current_message_id = int(envelopes[0]['id']) # Get the first envelope's ID self.current_message_id = int(envelopes[0]['id'])
else: else:
self.query_one("#main_content", Static).update("Failed to fetch the most recent message ID.") self.query_one("#main_content", Static).update("Failed to fetch the most recent message ID.")
except Exception as e: except Exception as e:

View File

@@ -13,3 +13,11 @@ Label#task_prompt_label {
Label#message_label { Label#message_label {
padding: 1; padding: 1;
} }
StatusTitle {
width: 100%;
height: 1;
color: $text;
background: $surface;
content-align: center middle;
}

View File

@@ -20,7 +20,6 @@ class CreateTaskScreen(Screen[str]):
task_args = input_widget.value task_args = input_widget.value
self.dismiss(task_args) self.dismiss(task_args)
@on(Input._on_key) def on_key(self, event) -> None:
def handle_close(self, event) -> None:
if (event.key == "escape" or event.key == "ctrl+c"): if (event.key == "escape" or event.key == "ctrl+c"):
self.dismiss() self.dismiss()