layout of panels tweaked
This commit is contained in:
@@ -97,6 +97,9 @@ def synchronize_maildir(maildir_path, headers):
|
|||||||
)
|
)
|
||||||
if response.status_code != 201: # 201 Created indicates success
|
if response.status_code != 201: # 201 Created indicates success
|
||||||
print(f"Failed to move message to 'Archive': {message_id}, {response.status_code}, {response.text}")
|
print(f"Failed to move message to 'Archive': {message_id}, {response.status_code}, {response.text}")
|
||||||
|
if response.status_code == 404:
|
||||||
|
os.remove(filepath) # Remove the file from local archive if not found on server
|
||||||
|
|
||||||
|
|
||||||
# Save the current sync timestamp
|
# Save the current sync timestamp
|
||||||
save_sync_timestamp()
|
save_sync_timestamp()
|
||||||
@@ -311,7 +314,7 @@ new_files = set(glob.glob(os.path.join(new_dir, '*.eml')))
|
|||||||
cur_files = set(glob.glob(os.path.join(cur_dir, '*.eml')))
|
cur_files = set(glob.glob(os.path.join(cur_dir, '*.eml')))
|
||||||
|
|
||||||
for filename in Set.union(cur_files, new_files):
|
for filename in Set.union(cur_files, new_files):
|
||||||
message_id = filename.split('.')[0] # Extract the Message-ID from the filename
|
message_id = filename.split('.')[0].split('/')[-1] # Extract the Message-ID from the filename
|
||||||
if (message_id not in inbox_msg_ids):
|
if (message_id not in inbox_msg_ids):
|
||||||
print(f"Deleting {filename} from inbox")
|
print(f"Deleting {filename} from inbox")
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
|
|||||||
Binary file not shown.
@@ -3,10 +3,12 @@ from maildir_gtd.screens.OpenMessage import OpenMessageScreen
|
|||||||
|
|
||||||
def action_open(app) -> None:
|
def action_open(app) -> None:
|
||||||
"""Show the input modal for opening a specific message by ID."""
|
"""Show the input modal for opening a specific message by ID."""
|
||||||
def check_id(message_id: str) -> bool:
|
def check_id(message_id: str | None) -> bool:
|
||||||
try:
|
try:
|
||||||
int(message_id)
|
int(message_id)
|
||||||
app.show_message(message_id)
|
app.show_message(message_id)
|
||||||
|
if (message_id is not None and message_id > 0):
|
||||||
|
app.show_message(message_id)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
app.bell()
|
app.bell()
|
||||||
app.show_status("Invalid message ID. Please enter an integer.", severity="error")
|
app.show_status("Invalid message ID. Please enter an integer.", severity="error")
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from textual.widgets import Footer, Static, Label, Markdown, ListView, ListItem
|
|||||||
from textual.reactive import reactive, Reactive
|
from textual.reactive import reactive, Reactive
|
||||||
from textual.binding import Binding
|
from textual.binding import Binding
|
||||||
from textual.timer import Timer
|
from textual.timer import Timer
|
||||||
from textual.containers import ScrollableContainer, Grid
|
from textual.containers import ScrollableContainer, Grid, Vertical, Horizontal
|
||||||
|
|
||||||
from actions.archive import archive_current
|
from actions.archive import archive_current
|
||||||
from actions.delete import delete_current
|
from actions.delete import delete_current
|
||||||
@@ -48,7 +48,6 @@ class EmailViewerApp(App):
|
|||||||
"""A simple email viewer app using the Himalaya CLI."""
|
"""A simple email viewer app using the Himalaya CLI."""
|
||||||
CSS_PATH = "email_viewer.tcss"
|
CSS_PATH = "email_viewer.tcss"
|
||||||
title = "Maildir GTD Reader"
|
title = "Maildir GTD Reader"
|
||||||
|
|
||||||
current_message_id: Reactive[int] = reactive(0)
|
current_message_id: Reactive[int] = reactive(0)
|
||||||
current_message_index: Reactive[int] = reactive(0)
|
current_message_index: Reactive[int] = reactive(0)
|
||||||
folder = reactive("INBOX")
|
folder = reactive("INBOX")
|
||||||
@@ -61,6 +60,8 @@ class EmailViewerApp(App):
|
|||||||
newest_id: Reactive[int] = reactive(0)
|
newest_id: Reactive[int] = reactive(0)
|
||||||
msg_worker: Worker | None = None
|
msg_worker: Worker | None = None
|
||||||
message_body_cache: dict[int, str] = {}
|
message_body_cache: dict[int, str] = {}
|
||||||
|
total_messages: Reactive[int] = reactive(0)
|
||||||
|
status_title = reactive("Message View")
|
||||||
|
|
||||||
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)
|
||||||
@@ -72,7 +73,7 @@ class EmailViewerApp(App):
|
|||||||
yield SystemCommand("Create Task", "Create a task using the task CLI", self.action_create_task)
|
yield SystemCommand("Create Task", "Create a task using the task CLI", self.action_create_task)
|
||||||
yield SystemCommand("Oldest Message", "Show the oldest message", self.action_oldest)
|
yield SystemCommand("Oldest Message", "Show the oldest message", self.action_oldest)
|
||||||
yield SystemCommand("Newest Message", "Show the newest message", self.action_newest)
|
yield SystemCommand("Newest Message", "Show the newest message", self.action_newest)
|
||||||
yield SystemCommand("Reload", "Reload the message list", self.action_fetch_list)
|
yield SystemCommand("Reload", "Reload the message list", self.fetch_envelopes)
|
||||||
|
|
||||||
BINDINGS = [
|
BINDINGS = [
|
||||||
Binding("j", "next", "Next message"),
|
Binding("j", "next", "Next message"),
|
||||||
@@ -83,26 +84,31 @@ class EmailViewerApp(App):
|
|||||||
Binding("q", "quit", "Quit application"),
|
Binding("q", "quit", "Quit application"),
|
||||||
Binding("h", "toggle_header", "Toggle Envelope Header"),
|
Binding("h", "toggle_header", "Toggle Envelope Header"),
|
||||||
Binding("t", "create_task", "Create Task"),
|
Binding("t", "create_task", "Create Task"),
|
||||||
Binding("ctrl-r", "reload", "Reload message list")
|
Binding("%", "reload", "Reload message list"),
|
||||||
|
Binding("1", "focus_1", "Focus Accounts Panel"),
|
||||||
|
Binding("2", "focus_2", "Focus Folders Panel"),
|
||||||
|
Binding("3", "focus_3", "Focus Envelopes Panel")
|
||||||
]
|
]
|
||||||
|
|
||||||
BINDINGS.extend([
|
BINDINGS.extend([
|
||||||
Binding("down", "scroll_down", "Scroll down"),
|
|
||||||
Binding("up", "scroll_up", "Scroll up"),
|
|
||||||
Binding("space", "scroll_page_down", "Scroll page down"),
|
Binding("space", "scroll_page_down", "Scroll page down"),
|
||||||
Binding("b", "scroll_page_up", "Scroll page up")
|
Binding("b", "scroll_page_up", "Scroll page up")
|
||||||
])
|
])
|
||||||
|
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
"""Create child widgets for the app."""
|
yield Horizontal(
|
||||||
yield Grid(
|
Vertical(
|
||||||
ListView(ListItem(Label("All emails...")), id="list_view", initial_index=0),
|
ListView(ListItem(Label("All emails...")), id="envelopes_list", classes="list_view", initial_index=0),
|
||||||
|
ListView(id="accounts_list", classes="list_view"),
|
||||||
|
ListView(id="folders_list", classes="list_view"),
|
||||||
|
id="sidebar"
|
||||||
|
),
|
||||||
ScrollableContainer(
|
ScrollableContainer(
|
||||||
StatusTitle().data_bind(EmailViewerApp.current_message_id),
|
|
||||||
EnvelopeHeader(),
|
EnvelopeHeader(),
|
||||||
Markdown(),
|
Markdown(),
|
||||||
id="main_content",
|
id="main_content"
|
||||||
)
|
),
|
||||||
|
id="outer-wrapper"
|
||||||
)
|
)
|
||||||
yield Footer()
|
yield Footer()
|
||||||
|
|
||||||
@@ -110,13 +116,28 @@ class EmailViewerApp(App):
|
|||||||
self.alert_timer: Timer | None = None # Timer to throttle alerts
|
self.alert_timer: Timer | None = None # Timer to throttle alerts
|
||||||
self.theme = "monokai"
|
self.theme = "monokai"
|
||||||
self.title = "MaildirGTD"
|
self.title = "MaildirGTD"
|
||||||
|
self.query_one("#main_content").border_title = self.status_title
|
||||||
|
self.query_one("#envelopes_list").border_title = "\[1] Emails"
|
||||||
|
self.query_one("#accounts_list").border_title = "\[2] Accounts"
|
||||||
|
|
||||||
|
self.query_one("#folders_list").border_title = "\[3] Folders"
|
||||||
|
|
||||||
# self.query_one(ListView).data_bind(index=EmailViewerApp.current_message_index)
|
# self.query_one(ListView).data_bind(index=EmailViewerApp.current_message_index)
|
||||||
# self.watch(self.query_one(StatusTitle), "current_message_id", update_progress)
|
# 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
|
||||||
worker = self.action_fetch_list()
|
self.fetch_accounts()
|
||||||
|
self.fetch_folders()
|
||||||
|
worker = self.fetch_envelopes()
|
||||||
await worker.wait()
|
await worker.wait()
|
||||||
|
self.query_one("#envelopes_list").focus()
|
||||||
self.action_oldest()
|
self.action_oldest()
|
||||||
|
|
||||||
|
def compute_status_title(self) -> None:
|
||||||
|
return f"Message ID: {self.current_message_id} | [b]{self.current_message_index}[/b]/{self.total_messages}"
|
||||||
|
|
||||||
|
def watch_status_title(self, old_status_title: str, new_status_title: str) -> None:
|
||||||
|
self.query_one("#main_content").border_title = new_status_title
|
||||||
|
|
||||||
def compute_newest_id(self) -> None:
|
def compute_newest_id(self) -> None:
|
||||||
if not self.all_envelopes:
|
if not self.all_envelopes:
|
||||||
return 0
|
return 0
|
||||||
@@ -146,7 +167,7 @@ class EmailViewerApp(App):
|
|||||||
def watch_reload_needed(self, old_reload_needed: bool, new_reload_needed: bool) -> None:
|
def watch_reload_needed(self, old_reload_needed: bool, new_reload_needed: bool) -> None:
|
||||||
logging.info(f"Reload needed: {new_reload_needed}")
|
logging.info(f"Reload needed: {new_reload_needed}")
|
||||||
if (old_reload_needed == False and new_reload_needed == True):
|
if (old_reload_needed == False and new_reload_needed == True):
|
||||||
self.action_fetch_list()
|
self.fetch_envelopes()
|
||||||
|
|
||||||
|
|
||||||
def watch_current_message_id(self, old_message_id: int, new_message_id: int) -> None:
|
def watch_current_message_id(self, old_message_id: int, new_message_id: int) -> None:
|
||||||
@@ -165,7 +186,7 @@ class EmailViewerApp(App):
|
|||||||
headers.to = envelope['to']['addr']
|
headers.to = envelope['to']['addr']
|
||||||
headers.date = datetime.strptime(envelope['date'].replace("+00:00", ""), "%Y-%m-%d %H:%M").strftime("%a %b %d %H:%M")
|
headers.date = datetime.strptime(envelope['date'].replace("+00:00", ""), "%Y-%m-%d %H:%M").strftime("%a %b %d %H:%M")
|
||||||
headers.cc = envelope['cc']['addr'] if 'cc' in envelope else ""
|
headers.cc = envelope['cc']['addr'] if 'cc' in envelope else ""
|
||||||
self.query_one(StatusTitle).current_message_index = index
|
# self.query_one(StatusTitle).current_message_index = index
|
||||||
self.query_one(ListView).index = index
|
self.query_one(ListView).index = index
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -211,8 +232,8 @@ class EmailViewerApp(App):
|
|||||||
logging.error(f"Error fetching message content: {e}")
|
logging.error(f"Error fetching message content: {e}")
|
||||||
|
|
||||||
@work(exclusive=False)
|
@work(exclusive=False)
|
||||||
async def action_fetch_list(self) -> None:
|
async def fetch_envelopes(self) -> None:
|
||||||
msglist = self.query_one(ListView)
|
msglist = self.query_one("#envelopes_list")
|
||||||
try:
|
try:
|
||||||
msglist.loading = True
|
msglist.loading = True
|
||||||
process = await asyncio.create_subprocess_shell(
|
process = await asyncio.create_subprocess_shell(
|
||||||
@@ -227,8 +248,7 @@ class EmailViewerApp(App):
|
|||||||
envelopes = json.loads(stdout.decode())
|
envelopes = json.loads(stdout.decode())
|
||||||
if envelopes:
|
if envelopes:
|
||||||
self.reload_needed = False
|
self.reload_needed = False
|
||||||
status = self.query_one(StatusTitle)
|
self.total_messages = len(envelopes)
|
||||||
status.total_messages = len(envelopes)
|
|
||||||
msglist.clear()
|
msglist.clear()
|
||||||
envelopes = sorted(envelopes, key=lambda x: int(x['id']))
|
envelopes = sorted(envelopes, key=lambda x: int(x['id']))
|
||||||
self.all_envelopes = envelopes
|
self.all_envelopes = envelopes
|
||||||
@@ -243,7 +263,55 @@ class EmailViewerApp(App):
|
|||||||
finally:
|
finally:
|
||||||
msglist.loading = False
|
msglist.loading = False
|
||||||
|
|
||||||
|
@work(exclusive=False)
|
||||||
|
async def fetch_accounts(self) -> None:
|
||||||
|
accounts_list = self.query_one("#accounts_list")
|
||||||
|
try:
|
||||||
|
accounts_list.loading = True
|
||||||
|
process = await asyncio.create_subprocess_shell(
|
||||||
|
"himalaya account list -o json",
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE
|
||||||
|
)
|
||||||
|
stdout, stderr = await process.communicate()
|
||||||
|
logging.info(f"stdout: {stdout.decode()[0:50]}")
|
||||||
|
if process.returncode == 0:
|
||||||
|
import json
|
||||||
|
accounts = json.loads(stdout.decode())
|
||||||
|
if accounts:
|
||||||
|
for account in accounts:
|
||||||
|
item = ListItem(Label(str(account['name']).strip(), classes="account_name", markup=False))
|
||||||
|
accounts_list.append(item)
|
||||||
|
except Exception as e:
|
||||||
|
self.show_status(f"Error fetching account list: {e}", "error")
|
||||||
|
finally:
|
||||||
|
accounts_list.loading = False
|
||||||
|
|
||||||
|
@work(exclusive=False)
|
||||||
|
async def fetch_folders(self) -> None:
|
||||||
|
folders_list = self.query_one("#folders_list")
|
||||||
|
folders_list.clear()
|
||||||
|
folders_list.append(ListItem(Label("INBOX", classes="folder_name", markup=False)))
|
||||||
|
try:
|
||||||
|
folders_list.loading = True
|
||||||
|
process = await asyncio.create_subprocess_shell(
|
||||||
|
"himalaya folder list -o json",
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE
|
||||||
|
)
|
||||||
|
stdout, stderr = await process.communicate()
|
||||||
|
logging.info(f"stdout: {stdout.decode()[0:50]}")
|
||||||
|
if process.returncode == 0:
|
||||||
|
import json
|
||||||
|
folders = json.loads(stdout.decode())
|
||||||
|
if folders:
|
||||||
|
for folder in folders:
|
||||||
|
item = ListItem(Label(str(folder['name']).strip(), classes="folder_name", markup=False))
|
||||||
|
folders_list.append(item)
|
||||||
|
except Exception as e:
|
||||||
|
self.show_status(f"Error fetching folder list: {e}", "error")
|
||||||
|
finally:
|
||||||
|
folders_list.loading = False
|
||||||
|
|
||||||
def show_message(self, message_id: int) -> None:
|
def show_message(self, message_id: int) -> None:
|
||||||
self.current_message_id = message_id
|
self.current_message_id = message_id
|
||||||
@@ -260,22 +328,22 @@ class EmailViewerApp(App):
|
|||||||
|
|
||||||
def action_next(self) -> None:
|
def action_next(self) -> None:
|
||||||
self.show_message(self.next_id)
|
self.show_message(self.next_id)
|
||||||
self.action_fetch_list() if self.reload_needed else None
|
self.fetch_envelopes() if self.reload_needed else None
|
||||||
|
|
||||||
def action_previous(self) -> None:
|
def action_previous(self) -> None:
|
||||||
self.action_fetch_list() if self.reload_needed else None
|
self.fetch_envelopes() if self.reload_needed else None
|
||||||
self.show_message(self.previous_id)
|
self.show_message(self.previous_id)
|
||||||
|
|
||||||
def action_delete(self) -> None:
|
def action_delete(self) -> None:
|
||||||
self.all_envelopes.remove(self.all_envelopes[self.current_message_index])
|
self.all_envelopes.remove(self.all_envelopes[self.current_message_index])
|
||||||
self.message_body_cache.pop(self.current_message_id, None)
|
self.message_body_cache.pop(self.current_message_id, None)
|
||||||
self.query_one(StatusTitle).total_messages = len(self.all_envelopes)
|
self.total_messages = len(self.all_envelopes)
|
||||||
delete_current(self)
|
delete_current(self)
|
||||||
|
|
||||||
def action_archive(self) -> None:
|
def action_archive(self) -> None:
|
||||||
self.all_envelopes.remove(self.all_envelopes[self.current_message_index])
|
self.all_envelopes.remove(self.all_envelopes[self.current_message_index])
|
||||||
self.message_body_cache.pop(self.current_message_id, None)
|
self.message_body_cache.pop(self.current_message_id, None)
|
||||||
self.query_one(StatusTitle).total_messages = len(self.all_envelopes)
|
self.total_messages = len(self.all_envelopes)
|
||||||
archive_current(self)
|
archive_current(self)
|
||||||
|
|
||||||
def action_open(self) -> None:
|
def action_open(self) -> None:
|
||||||
@@ -306,13 +374,22 @@ class EmailViewerApp(App):
|
|||||||
self.exit()
|
self.exit()
|
||||||
|
|
||||||
def action_oldest(self) -> None:
|
def action_oldest(self) -> None:
|
||||||
self.action_fetch_list() if self.reload_needed else None
|
self.fetch_envelopes() if self.reload_needed else None
|
||||||
self.show_message(self.oldest_id)
|
self.show_message(self.oldest_id)
|
||||||
|
|
||||||
def action_newest(self) -> None:
|
def action_newest(self) -> None:
|
||||||
self.action_fetch_list() if self.reload_needed else None
|
self.fetch_envelopes() if self.reload_needed else None
|
||||||
self.show_message(self.newest_id)
|
self.show_message(self.newest_id)
|
||||||
|
|
||||||
|
def action_focus_1(self) -> None:
|
||||||
|
self.query_one("#envelopes_list").focus()
|
||||||
|
|
||||||
|
def action_focus_2(self) -> None:
|
||||||
|
self.query_one("#accounts_list").focus()
|
||||||
|
|
||||||
|
def action_focus_3(self) -> None:
|
||||||
|
self.query_one("#folders_list").focus()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = EmailViewerApp()
|
app = EmailViewerApp()
|
||||||
app.run()
|
app.run()
|
||||||
|
|||||||
@@ -1,5 +1,37 @@
|
|||||||
/* Basic stylesheet for the Textual Email Viewer App */
|
/* Basic stylesheet for the Textual Email Viewer App */
|
||||||
|
|
||||||
|
|
||||||
|
#main_content, .list_view {
|
||||||
|
scrollbar-size: 1 1;
|
||||||
|
border: round rgb(117, 106, 129);
|
||||||
|
height: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar {
|
||||||
|
width: 1fr
|
||||||
|
}
|
||||||
|
|
||||||
|
#main_content {
|
||||||
|
width: 2fr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar:focus-within {
|
||||||
|
background: $panel;
|
||||||
|
.list_view:blur {
|
||||||
|
height: 3;
|
||||||
|
}
|
||||||
|
.list_view:focus {
|
||||||
|
height: 2fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#main_content:focus, .list_view:focus {
|
||||||
|
border: round $secondary;
|
||||||
|
background: rgb(55, 53, 57);
|
||||||
|
border-title-style: bold;
|
||||||
|
}
|
||||||
|
|
||||||
Label#task_prompt {
|
Label#task_prompt {
|
||||||
padding: 1;
|
padding: 1;
|
||||||
color: rgb(128,128,128);
|
color: rgb(128,128,128);
|
||||||
@@ -25,7 +57,6 @@ StatusTitle {
|
|||||||
|
|
||||||
EnvelopeHeader {
|
EnvelopeHeader {
|
||||||
dock: top;
|
dock: top;
|
||||||
margin-top: 1;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-height: 2;
|
max-height: 2;
|
||||||
tint: $primary 10%;
|
tint: $primary 10%;
|
||||||
@@ -35,21 +66,15 @@ Markdown {
|
|||||||
padding: 1 2;
|
padding: 1 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
|
||||||
dock: left;
|
|
||||||
width: 30%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.email_subject {
|
.email_subject {
|
||||||
width: 100%;
|
width: 1fr;
|
||||||
padding: 0
|
padding: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
.header_key {
|
.header_key {
|
||||||
tint: gray 20%;
|
tint: gray 20%;
|
||||||
min-width: 10;
|
min-width: 10;
|
||||||
|
text-style:bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header_value {
|
.header_value {
|
||||||
@@ -57,3 +82,32 @@ ListView {
|
|||||||
height: auto;
|
height: auto;
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal_screen {
|
||||||
|
align: center middle;
|
||||||
|
margin: 1;
|
||||||
|
padding: 2;
|
||||||
|
border: round $border;
|
||||||
|
background: $panel;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#create_task_container {
|
||||||
|
width: 50%;
|
||||||
|
height: 50%;
|
||||||
|
border: heavy $secondary;
|
||||||
|
layout: horizontal;
|
||||||
|
align: center middle;
|
||||||
|
Label {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
Input {
|
||||||
|
width: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#envelopes-list ListItem:odd {
|
||||||
|
background: rgb(25, 24, 26);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,24 @@
|
|||||||
from textual import on
|
from textual import on
|
||||||
from textual.app import ComposeResult, Screen
|
from textual.app import ComposeResult
|
||||||
from textual.widgets import Input, Label
|
from textual.screen import ModalScreen
|
||||||
from textual.containers import Horizontal
|
from textual.widgets import Input, Label, Button
|
||||||
|
from textual.containers import Horizontal, Vertical
|
||||||
|
|
||||||
|
|
||||||
class CreateTaskScreen(Screen[str]):
|
class CreateTaskScreen(ModalScreen[str]):
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
yield Horizontal(
|
yield Vertical(
|
||||||
|
Horizontal(
|
||||||
Label("$>", id="task_prompt"),
|
Label("$>", id="task_prompt"),
|
||||||
Label("task add ", id="task_prompt_label"),
|
Label("task add ", id="task_prompt_label"),
|
||||||
Input(placeholder="arguments", id="task_input")
|
Input(placeholder="arguments", id="task_input"),
|
||||||
|
),
|
||||||
|
Horizontal(
|
||||||
|
Button("Cancel"),
|
||||||
|
Button("Submit")
|
||||||
|
),
|
||||||
|
id="create_task_container",
|
||||||
|
classes="modal_screen"
|
||||||
)
|
)
|
||||||
|
|
||||||
@on(Input.Submitted)
|
@on(Input.Submitted)
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
from textual import on
|
from textual import on
|
||||||
from textual.app import ComposeResult, Screen
|
from textual.app import ComposeResult
|
||||||
|
from textual.screen import ModalScreen
|
||||||
from textual.widgets import Input, Label, Button
|
from textual.widgets import Input, Label, Button
|
||||||
from textual.containers import Horizontal
|
from textual.containers import Container
|
||||||
|
|
||||||
|
class OpenMessageScreen(ModalScreen[int | None]):
|
||||||
|
|
||||||
class OpenMessageScreen(Screen[int]):
|
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
yield Horizontal(
|
yield Container(
|
||||||
Label("📨", id="message_label"),
|
Label("📨", id="message_label"),
|
||||||
Input(placeholder="Enter message ID (integer only)", type="integer", id="open_message_input"),
|
Input(placeholder="Enter message ID (integer only)", type="integer", id="open_message_input"),
|
||||||
Button("Open", variant="primary", id="open_message_button")
|
Button("Open", variant="primary", id="open_message_button"),
|
||||||
|
id="open_message_container",
|
||||||
|
classes="modal_screen"
|
||||||
)
|
)
|
||||||
|
|
||||||
@on(Input.Submitted)
|
@on(Input.Submitted)
|
||||||
def handle_message_id(self) -> None:
|
def handle_message_id(self) -> None:
|
||||||
input_widget = self.query_one("#open_message_input", Input)
|
input_widget = self.query_one("#open_message_input", Input)
|
||||||
self.disabled = True
|
message_id = int(input_widget.value if input_widget.value else 0)
|
||||||
self.loading = True
|
|
||||||
message_id = int(input_widget.value)
|
|
||||||
self.dismiss(message_id)
|
self.dismiss(message_id)
|
||||||
|
|
||||||
@on(Input._on_key)
|
@on(Input._on_key)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user