bug fix display and load
This commit is contained in:
@@ -22,7 +22,7 @@ async def delete_current(app):
|
|||||||
next_id, next_idx = app.message_store.find_prev_valid_id(current_index)
|
next_id, next_idx = app.message_store.find_prev_valid_id(current_index)
|
||||||
|
|
||||||
# Delete the message using our Himalaya client module
|
# Delete the message using our Himalaya client module
|
||||||
success = await himalaya_client.delete_message(current_message_id)
|
message, success = await himalaya_client.delete_message(current_message_id)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
app.show_status(f"Message {current_message_id} deleted.", "success")
|
app.show_status(f"Message {current_message_id} deleted.", "success")
|
||||||
@@ -38,4 +38,6 @@ async def delete_current(app):
|
|||||||
app.current_message_id = 0
|
app.current_message_id = 0
|
||||||
app.show_status("No more messages available.", "warning")
|
app.show_status("No more messages available.", "warning")
|
||||||
else:
|
else:
|
||||||
app.show_status(f"Failed to delete message {current_message_id}.", "error")
|
app.show_status(
|
||||||
|
f"Failed to delete message {current_message_id}: {message}", "error"
|
||||||
|
)
|
||||||
|
|||||||
@@ -250,8 +250,16 @@ class EmailViewerApp(App):
|
|||||||
if event.list_view.index is None:
|
if event.list_view.index is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Only handle selection from the envelopes list
|
||||||
|
if event.list_view.id != "envelopes_list":
|
||||||
|
return
|
||||||
|
|
||||||
selected_index = event.list_view.index
|
selected_index = event.list_view.index
|
||||||
|
|
||||||
|
# Check bounds before accessing
|
||||||
|
if selected_index < 0 or selected_index >= len(self.message_store.envelopes):
|
||||||
|
return
|
||||||
|
|
||||||
current_item = self.message_store.envelopes[selected_index]
|
current_item = self.message_store.envelopes[selected_index]
|
||||||
|
|
||||||
if current_item is None or current_item.get("type") == "header":
|
if current_item is None or current_item.get("type") == "header":
|
||||||
@@ -261,13 +269,26 @@ class EmailViewerApp(App):
|
|||||||
self.current_message_id = message_id
|
self.current_message_id = message_id
|
||||||
self.current_message_index = selected_index
|
self.current_message_index = selected_index
|
||||||
|
|
||||||
|
# Focus the main content panel after selecting a message
|
||||||
|
self.action_focus_4()
|
||||||
|
|
||||||
def on_list_view_highlighted(self, event: ListView.Highlighted) -> None:
|
def on_list_view_highlighted(self, event: ListView.Highlighted) -> None:
|
||||||
"""Called when an item in the list view is highlighted (e.g., via arrow keys)."""
|
"""Called when an item in the list view is highlighted (e.g., via arrow keys)."""
|
||||||
if event.list_view.index is None:
|
if event.list_view.index is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Only handle highlights from the envelopes list
|
||||||
|
if event.list_view.id != "envelopes_list":
|
||||||
|
return
|
||||||
|
|
||||||
highlighted_index = event.list_view.index
|
highlighted_index = event.list_view.index
|
||||||
|
|
||||||
|
# Check bounds before accessing
|
||||||
|
if highlighted_index < 0 or highlighted_index >= len(
|
||||||
|
self.message_store.envelopes
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
current_item = self.message_store.envelopes[highlighted_index]
|
current_item = self.message_store.envelopes[highlighted_index]
|
||||||
|
|
||||||
if current_item is None or current_item.get("type") == "header":
|
if current_item is None or current_item.get("type") == "header":
|
||||||
|
|||||||
@@ -89,6 +89,13 @@ class LinkPanelConfig(BaseModel):
|
|||||||
close_on_open: bool = False
|
close_on_open: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class MailConfig(BaseModel):
|
||||||
|
"""Configuration for mail operations."""
|
||||||
|
|
||||||
|
# Folder to move messages to when archiving
|
||||||
|
archive_folder: str = "Archive"
|
||||||
|
|
||||||
|
|
||||||
class ThemeConfig(BaseModel):
|
class ThemeConfig(BaseModel):
|
||||||
"""Theme/appearance settings."""
|
"""Theme/appearance settings."""
|
||||||
|
|
||||||
@@ -104,6 +111,7 @@ class MaildirGTDConfig(BaseModel):
|
|||||||
)
|
)
|
||||||
content_display: ContentDisplayConfig = Field(default_factory=ContentDisplayConfig)
|
content_display: ContentDisplayConfig = Field(default_factory=ContentDisplayConfig)
|
||||||
link_panel: LinkPanelConfig = Field(default_factory=LinkPanelConfig)
|
link_panel: LinkPanelConfig = Field(default_factory=LinkPanelConfig)
|
||||||
|
mail: MailConfig = Field(default_factory=MailConfig)
|
||||||
keybindings: KeybindingsConfig = Field(default_factory=KeybindingsConfig)
|
keybindings: KeybindingsConfig = Field(default_factory=KeybindingsConfig)
|
||||||
theme: ThemeConfig = Field(default_factory=ThemeConfig)
|
theme: ThemeConfig = Field(default_factory=ThemeConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -11,17 +11,23 @@
|
|||||||
width: 1fr
|
width: 1fr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list_view {
|
||||||
|
height: 3;
|
||||||
|
}
|
||||||
|
|
||||||
#main_content {
|
#main_content {
|
||||||
width: 2fr;
|
width: 2fr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.envelope-selected {
|
.envelope-selected {
|
||||||
tint: $accent 20%;
|
tint: $accent 20%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar:focus-within {
|
#sidebar:focus-within {
|
||||||
background: $panel;
|
background: $panel;
|
||||||
|
|
||||||
.list_view:blur {
|
.list_view:blur {
|
||||||
height: 3;
|
height: 3;
|
||||||
}
|
}
|
||||||
@@ -30,6 +36,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#envelopes_list {
|
||||||
|
height: 2fr;
|
||||||
|
}
|
||||||
|
|
||||||
#main_content:focus, .list_view:focus {
|
#main_content:focus, .list_view:focus {
|
||||||
border: round $secondary;
|
border: round $secondary;
|
||||||
background: rgb(55, 53, 57);
|
background: rgb(55, 53, 57);
|
||||||
|
|||||||
@@ -147,6 +147,9 @@ class EnvelopeListItem(Static):
|
|||||||
date_str = date_str.replace("Z", "+00:00")
|
date_str = date_str.replace("Z", "+00:00")
|
||||||
dt = datetime.fromisoformat(date_str)
|
dt = datetime.fromisoformat(date_str)
|
||||||
|
|
||||||
|
# Convert to local timezone
|
||||||
|
dt = dt.astimezone()
|
||||||
|
|
||||||
parts = []
|
parts = []
|
||||||
if self.config.show_date:
|
if self.config.show_date:
|
||||||
parts.append(dt.strftime(self.config.date_format))
|
parts.append(dt.strftime(self.config.date_format))
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
from src.maildir_gtd.config import get_config
|
||||||
|
|
||||||
|
|
||||||
async def list_envelopes(limit: int = 9999) -> Tuple[List[Dict[str, Any]], bool]:
|
async def list_envelopes(limit: int = 9999) -> Tuple[List[Dict[str, Any]], bool]:
|
||||||
"""
|
"""
|
||||||
@@ -92,7 +94,7 @@ async def list_folders() -> Tuple[List[Dict[str, Any]], bool]:
|
|||||||
return [], False
|
return [], False
|
||||||
|
|
||||||
|
|
||||||
async def delete_message(message_id: int) -> bool:
|
async def delete_message(message_id: int) -> Tuple[Optional[str], bool]:
|
||||||
"""
|
"""
|
||||||
Delete a message by its ID.
|
Delete a message by its ID.
|
||||||
|
|
||||||
@@ -100,7 +102,9 @@ async def delete_message(message_id: int) -> bool:
|
|||||||
message_id: The ID of the message to delete
|
message_id: The ID of the message to delete
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if deletion was successful, False otherwise
|
Tuple containing:
|
||||||
|
- Result message or error
|
||||||
|
- Success status (True if deletion was successful)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
process = await asyncio.create_subprocess_shell(
|
process = await asyncio.create_subprocess_shell(
|
||||||
@@ -110,10 +114,15 @@ async def delete_message(message_id: int) -> bool:
|
|||||||
)
|
)
|
||||||
stdout, stderr = await process.communicate()
|
stdout, stderr = await process.communicate()
|
||||||
|
|
||||||
return process.returncode == 0
|
if process.returncode == 0:
|
||||||
|
return stdout.decode().strip() or "Deleted successfully", True
|
||||||
|
else:
|
||||||
|
error_msg = stderr.decode().strip()
|
||||||
|
logging.error(f"Error deleting message: {error_msg}")
|
||||||
|
return error_msg or "Unknown error", False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Exception during message deletion: {e}")
|
logging.error(f"Exception during message deletion: {e}")
|
||||||
return False
|
return str(e), False
|
||||||
|
|
||||||
|
|
||||||
# async def archive_message(message_id: int) -> [str, bool]:
|
# async def archive_message(message_id: int) -> [str, bool]:
|
||||||
@@ -151,8 +160,10 @@ async def archive_messages(message_ids: List[str]) -> Tuple[Optional[str], bool]
|
|||||||
A tuple containing an optional output string and a boolean indicating success.
|
A tuple containing an optional output string and a boolean indicating success.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
config = get_config()
|
||||||
|
archive_folder = config.mail.archive_folder
|
||||||
ids_str = " ".join(message_ids)
|
ids_str = " ".join(message_ids)
|
||||||
cmd = f"himalaya message move Archives {ids_str}"
|
cmd = f"himalaya message move {archive_folder} {ids_str}"
|
||||||
|
|
||||||
process = await asyncio.create_subprocess_shell(
|
process = await asyncio.create_subprocess_shell(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -162,13 +173,14 @@ async def archive_messages(message_ids: List[str]) -> Tuple[Optional[str], bool]
|
|||||||
stdout, stderr = await process.communicate()
|
stdout, stderr = await process.communicate()
|
||||||
|
|
||||||
if process.returncode == 0:
|
if process.returncode == 0:
|
||||||
return stdout.decode(), True
|
return stdout.decode().strip() or "Archived successfully", True
|
||||||
else:
|
else:
|
||||||
logging.error(f"Error archiving messages: {stderr.decode()}")
|
error_msg = stderr.decode().strip()
|
||||||
return None, False
|
logging.error(f"Error archiving messages: {error_msg}")
|
||||||
|
return error_msg or "Unknown error", False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Exception during message archiving: {e}")
|
logging.error(f"Exception during message archiving: {e}")
|
||||||
return None, False
|
return str(e), False
|
||||||
|
|
||||||
|
|
||||||
async def get_message_content(message_id: int) -> Tuple[Optional[str], bool]:
|
async def get_message_content(message_id: int) -> Tuple[Optional[str], bool]:
|
||||||
|
|||||||
Reference in New Issue
Block a user