Categorize and normalize folder listing
This commit is contained in:
parent
8de661b3bb
commit
9e2c420461
|
@ -19,6 +19,9 @@ import (
|
||||||
|
|
||||||
type MailboxInfo struct {
|
type MailboxInfo struct {
|
||||||
*imap.MailboxInfo
|
*imap.MailboxInfo
|
||||||
|
|
||||||
|
Active bool
|
||||||
|
Unseen int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mbox *MailboxInfo) URL() *url.URL {
|
func (mbox *MailboxInfo) URL() *url.URL {
|
||||||
|
@ -27,6 +30,15 @@ func (mbox *MailboxInfo) URL() *url.URL {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mbox *MailboxInfo) HasAttr(flag string) bool {
|
||||||
|
for _, attr := range mbox.Attributes {
|
||||||
|
if attr == flag {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func listMailboxes(conn *imapclient.Client) ([]MailboxInfo, error) {
|
func listMailboxes(conn *imapclient.Client) ([]MailboxInfo, error) {
|
||||||
ch := make(chan *imap.MailboxInfo, 10)
|
ch := make(chan *imap.MailboxInfo, 10)
|
||||||
done := make(chan error, 1)
|
done := make(chan error, 1)
|
||||||
|
@ -36,7 +48,7 @@ func listMailboxes(conn *imapclient.Client) ([]MailboxInfo, error) {
|
||||||
|
|
||||||
var mailboxes []MailboxInfo
|
var mailboxes []MailboxInfo
|
||||||
for mbox := range ch {
|
for mbox := range ch {
|
||||||
mailboxes = append(mailboxes, MailboxInfo{mbox})
|
mailboxes = append(mailboxes, MailboxInfo{mbox, false, -1})
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := <-done; err != nil {
|
if err := <-done; err != nil {
|
||||||
|
@ -133,7 +145,7 @@ func getMailboxByType(conn *imapclient.Client, mboxType mailboxType) (*MailboxIn
|
||||||
if best == nil {
|
if best == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return &MailboxInfo{best}, nil
|
return &MailboxInfo{best, false, -1}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureMailboxSelected(conn *imapclient.Client, mboxName string) error {
|
func ensureMailboxSelected(conn *imapclient.Client, mboxName string) error {
|
||||||
|
|
|
@ -65,12 +65,57 @@ func registerRoutes(p *alps.GoPlugin) {
|
||||||
|
|
||||||
type MailboxRenderData struct {
|
type MailboxRenderData struct {
|
||||||
alps.BaseRenderData
|
alps.BaseRenderData
|
||||||
Mailbox *MailboxStatus
|
Mailbox *MailboxStatus
|
||||||
Inbox *MailboxStatus
|
Inbox *MailboxStatus
|
||||||
Mailboxes []MailboxInfo
|
CategorizedMailboxes CategorizedMailboxes
|
||||||
Messages []IMAPMessage
|
Mailboxes []MailboxInfo
|
||||||
PrevPage, NextPage int
|
Messages []IMAPMessage
|
||||||
Query string
|
PrevPage, NextPage int
|
||||||
|
Query string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Organizes mailboxes into common/uncommon categories
|
||||||
|
type CategorizedMailboxes struct {
|
||||||
|
Common struct {
|
||||||
|
Inbox *MailboxInfo
|
||||||
|
Drafts *MailboxInfo
|
||||||
|
Sent *MailboxInfo
|
||||||
|
Junk *MailboxInfo
|
||||||
|
Trash *MailboxInfo
|
||||||
|
Archive *MailboxInfo
|
||||||
|
}
|
||||||
|
Additional []*MailboxInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func categorizeMailboxes(mailboxes []MailboxInfo,
|
||||||
|
inbox *MailboxStatus, active *MailboxStatus) CategorizedMailboxes {
|
||||||
|
|
||||||
|
var out CategorizedMailboxes
|
||||||
|
mmap := map[string]**MailboxInfo{
|
||||||
|
"INBOX": &out.Common.Inbox,
|
||||||
|
"Drafts": &out.Common.Drafts,
|
||||||
|
"Sent": &out.Common.Sent,
|
||||||
|
"Junk": &out.Common.Junk,
|
||||||
|
"Trash": &out.Common.Trash,
|
||||||
|
"Archive": &out.Common.Archive,
|
||||||
|
}
|
||||||
|
for i, _ := range mailboxes {
|
||||||
|
// Populate unseen & active states
|
||||||
|
if mailboxes[i].Name == active.Name {
|
||||||
|
mailboxes[i].Unseen = int(active.Unseen)
|
||||||
|
mailboxes[i].Active = true
|
||||||
|
}
|
||||||
|
if mailboxes[i].Name == inbox.Name {
|
||||||
|
mailboxes[i].Unseen = int(inbox.Unseen)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ptr, ok := mmap[mailboxes[i].Name]; ok {
|
||||||
|
*ptr = &mailboxes[i]
|
||||||
|
} else {
|
||||||
|
out.Additional = append(out.Additional, &mailboxes[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleGetMailbox(ctx *alps.Context) error {
|
func handleGetMailbox(ctx *alps.Context) error {
|
||||||
|
@ -154,15 +199,18 @@ func handleGetMailbox(ctx *alps.Context) error {
|
||||||
title = fmt.Sprintf("(%d) %s", mbox.Unseen, title)
|
title = fmt.Sprintf("(%d) %s", mbox.Unseen, title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
categorized := categorizeMailboxes(mailboxes, inbox, mbox)
|
||||||
|
|
||||||
return ctx.Render(http.StatusOK, "mailbox.html", &MailboxRenderData{
|
return ctx.Render(http.StatusOK, "mailbox.html", &MailboxRenderData{
|
||||||
BaseRenderData: *alps.NewBaseRenderData(ctx).WithTitle(title),
|
BaseRenderData: *alps.NewBaseRenderData(ctx).WithTitle(title),
|
||||||
Mailbox: mbox,
|
Mailbox: mbox,
|
||||||
Inbox: inbox,
|
Inbox: inbox,
|
||||||
Mailboxes: mailboxes,
|
CategorizedMailboxes: categorized,
|
||||||
Messages: msgs,
|
Mailboxes: mailboxes,
|
||||||
PrevPage: prevPage,
|
Messages: msgs,
|
||||||
NextPage: nextPage,
|
PrevPage: prevPage,
|
||||||
Query: query,
|
NextPage: nextPage,
|
||||||
|
Query: query,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,8 @@ footer { text-align: right; }
|
||||||
|
|
||||||
|
|
||||||
aside { flex: 0 0 180px; }
|
aside { flex: 0 0 180px; }
|
||||||
aside a { width: 100%; display: block; padding: 0.4rem 0 0.4rem 0.5rem; }
|
aside a,
|
||||||
|
aside .noselect { width: 100%; display: block; padding: 0.4rem 0 0.4rem 0.5rem; }
|
||||||
aside a.active { font-weight: bold; color: black; text-decoration: none; }
|
aside a.active { font-weight: bold; color: black; text-decoration: none; }
|
||||||
aside img { display: block; }
|
aside img { display: block; }
|
||||||
main {
|
main {
|
||||||
|
|
|
@ -1,28 +1,43 @@
|
||||||
{{template "head.html" .}}
|
{{template "head.html" .}}
|
||||||
{{template "nav.html" .}}
|
{{template "nav.html" .}}
|
||||||
|
|
||||||
|
{{ define "mbox-link" }}
|
||||||
|
{{ if not (.HasAttr "\\Noselect") }}
|
||||||
|
<a href="{{.URL}}" {{ if .Active }}class="active"{{ end }}>
|
||||||
|
{{- if eq .Name "INBOX" -}}
|
||||||
|
Inbox
|
||||||
|
{{- else -}}
|
||||||
|
{{ .Name }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- if .HasAttr "\\HasChildren" }}/{{ end }}
|
||||||
|
|
||||||
|
{{ if and (ne .Unseen -1) (ne .Unseen 0) }}({{ .Unseen }}){{ end }}
|
||||||
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
<span class="noselect">
|
||||||
|
{{.Name}}{{- if .HasAttr "\\HasChildren" }}/{{ end }}
|
||||||
|
</span>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
<div class="page-wrap">
|
<div class="page-wrap">
|
||||||
<aside>
|
<aside>
|
||||||
<!-- the logo image, dimensions 200x32 may be present or not -->
|
<!-- the logo image, dimensions 200x32 may be present or not -->
|
||||||
<a href="/compose" class="new">Compose Mail</a>
|
<a href="/compose" class="new">Compose Mail</a>
|
||||||
{{range .Mailboxes}}
|
{{ with .CategorizedMailboxes }}
|
||||||
<a href="{{.URL}}" {{ if eq $.Mailbox.Name .Name }}class="active"{{ end }}>
|
{{ with .Common.Inbox }}{{ template "mbox-link" . }}{{ end}}
|
||||||
{{ if eq .Name "INBOX" }}
|
{{ with .Common.Drafts }}{{ template "mbox-link" . }}{{ end}}
|
||||||
Inbox
|
{{ with .Common.Sent }}{{ template "mbox-link" . }}{{ end}}
|
||||||
{{ else }}
|
{{ with .Common.Junk }}{{ template "mbox-link" . }}{{ end}}
|
||||||
{{ .Name }}
|
{{ with .Common.Trash }}{{ template "mbox-link" . }}{{ end}}
|
||||||
{{ end }}
|
{{ with .Common.Archive }}{{ template "mbox-link" . }}{{ end}}
|
||||||
|
{{ if .Additional }}
|
||||||
{{ $unseen := 0 }}
|
<hr />
|
||||||
{{ if eq .Name "INBOX" }}
|
{{ range .Additional }}
|
||||||
{{ $unseen = $.Inbox.Unseen }}
|
{{ template "mbox-link" . }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ if eq .Name $.Mailbox.Name }}
|
{{ end }}
|
||||||
{{ $unseen = $.Mailbox.Unseen }}
|
{{ end }}
|
||||||
{{ end }}
|
|
||||||
{{ if $unseen }}({{ $unseen }}){{ end }}
|
|
||||||
</a>
|
|
||||||
{{end}}
|
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
Loading…
Reference in a new issue