default to Inbox perspective, show GTD item detail, reduce toolbar

- default to Inbox perspective (not INBOX mailbox) after first sync
- selectItemForDetail bridges GTD item selection to detail pane by
  creating a synthetic ThreadSummary for email items
- reduce GTD toolbar from 5 to 3 buttons (defer, complete, discard),
  someday/project remain accessible via keyboard shortcuts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 12:56:19 +01:00
parent 3c21a4c461
commit c4374b42ea
2 changed files with 27 additions and 21 deletions

View File

@@ -194,6 +194,27 @@ final class MailViewModel {
startObservingThreads(accountId: accountConfig.id, mailboxId: mailbox.id)
}
func selectItemForDetail(_ item: ItemSummary?) {
guard let item else {
selectedThread = nil
messages = []
return
}
switch item {
case .email(let msg):
// Show the message directly in the detail pane
selectedThread = ThreadSummary(
id: msg.id, accountId: accountConfig?.id ?? "", subject: msg.subject,
lastDate: msg.date, messageCount: 1, unreadCount: 0,
senders: msg.from?.displayName ?? "", snippet: msg.snippet
)
messages = [msg]
case .task:
selectedThread = nil
messages = []
}
}
func selectPerspective(_ perspective: Perspective) {
selectedMailbox = nil
selectedThread = nil
@@ -238,6 +259,7 @@ final class MailViewModel {
}
private var isSyncing = false
private var hasLoadedInitialPerspective = false
func syncNow() async {
guard let coordinator, !isSyncing else { return }
@@ -249,9 +271,10 @@ final class MailViewModel {
// Reload mailboxes after sync (they may have been created on first sync)
if let accountConfig {
await loadMailboxes(accountId: accountConfig.id)
// On first sync, default to INBOX view
if selectedMailbox == nil, let inbox = mailboxes.first(where: { $0.name.lowercased() == "inbox" }) {
selectMailbox(inbox)
// On first sync, load Inbox perspective
if !hasLoadedInitialPerspective {
hasLoadedInitialPerspective = true
selectPerspective(.inbox)
}
}
} catch {

View File

@@ -56,6 +56,7 @@ struct ThreadListView: View {
get: { viewModel.selectedItem?.id },
set: { newId in
viewModel.selectedItem = viewModel.items.first { $0.id == newId }
viewModel.selectItemForDetail(viewModel.selectedItem)
}
)) { item in
ItemRow(item: item)
@@ -176,24 +177,6 @@ struct ThreadListView: View {
.keyboardShortcut("d", modifiers: [])
.help("Defer (d)")
Button {
if let item = selectedItemSummary {
viewModel.deferItem(item, until: nil)
}
} label: {
Label("Someday", systemImage: "moon.zzz")
}
.keyboardShortcut("d", modifiers: [.shift])
.help("Someday (⇧D)")
Button {
showLabelPicker = true
} label: {
Label("Project", systemImage: "folder.badge.plus")
}
.keyboardShortcut("p", modifiers: [])
.help("File to Project (p)")
Button {
if let item = selectedItemSummary {
viewModel.completeItem(item)