Ring bell when new messages arrive
Add a "new-message-bell" option to the UI section of aerc.conf. A new hook into the message store allows the msglist widget to detect new messages being added to the displayed list. When new messages are delivered, and the new-message-bell option is enabled (as it is by default), the terminal will beep.
This commit is contained in:
parent
2804f00001
commit
152f8c9519
9 changed files with 56 additions and 4 deletions
|
@ -37,6 +37,12 @@ empty-dirlist=(no folders)
|
||||||
# Default: false
|
# Default: false
|
||||||
mouse-enabled=false
|
mouse-enabled=false
|
||||||
|
|
||||||
|
#
|
||||||
|
# Ring the bell when new messages are received
|
||||||
|
#
|
||||||
|
# Default: yes
|
||||||
|
new-message-bell=true
|
||||||
|
|
||||||
[viewer]
|
[viewer]
|
||||||
#
|
#
|
||||||
# Specifies the pager to use when displaying emails. Note that some filters
|
# Specifies the pager to use when displaying emails. Note that some filters
|
||||||
|
|
|
@ -32,6 +32,7 @@ type UIConfig struct {
|
||||||
EmptyMessage string `ini:"empty-message"`
|
EmptyMessage string `ini:"empty-message"`
|
||||||
EmptyDirlist string `ini:"empty-dirlist"`
|
EmptyDirlist string `ini:"empty-dirlist"`
|
||||||
MouseEnabled bool `ini:"mouse-enabled"`
|
MouseEnabled bool `ini:"mouse-enabled"`
|
||||||
|
NewMessageBell bool `ini:"new-message-bell"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -344,6 +345,7 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
|
||||||
EmptyMessage: "(no messages)",
|
EmptyMessage: "(no messages)",
|
||||||
EmptyDirlist: "(no folders)",
|
EmptyDirlist: "(no folders)",
|
||||||
MouseEnabled: false,
|
MouseEnabled: false,
|
||||||
|
NewMessageBell: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
Viewer: ViewerConfig{
|
Viewer: ViewerConfig{
|
||||||
|
|
|
@ -105,6 +105,11 @@ These options are configured in the *[ui]* section of aerc.conf.
|
||||||
|
|
||||||
Default: false
|
Default: false
|
||||||
|
|
||||||
|
*new-message-bell*
|
||||||
|
Ring the bell when a new message is received.
|
||||||
|
|
||||||
|
Default: true
|
||||||
|
|
||||||
## VIEWER
|
## VIEWER
|
||||||
|
|
||||||
These options are configured in the *[viewer]* section of aerc.conf.
|
These options are configured in the *[viewer]* section of aerc.conf.
|
||||||
|
|
|
@ -33,12 +33,14 @@ type MessageStore struct {
|
||||||
pendingHeaders map[uint32]interface{}
|
pendingHeaders map[uint32]interface{}
|
||||||
worker *types.Worker
|
worker *types.Worker
|
||||||
|
|
||||||
triggerNewEmail func(*models.MessageInfo)
|
triggerNewEmail func(*models.MessageInfo)
|
||||||
|
triggerDirectoryChange func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMessageStore(worker *types.Worker,
|
func NewMessageStore(worker *types.Worker,
|
||||||
dirInfo *models.DirectoryInfo,
|
dirInfo *models.DirectoryInfo,
|
||||||
triggerNewEmail func(*models.MessageInfo)) *MessageStore {
|
triggerNewEmail func(*models.MessageInfo),
|
||||||
|
triggerDirectoryChange func()) *MessageStore {
|
||||||
|
|
||||||
return &MessageStore{
|
return &MessageStore{
|
||||||
Deleted: make(map[uint32]interface{}),
|
Deleted: make(map[uint32]interface{}),
|
||||||
|
@ -52,7 +54,8 @@ func NewMessageStore(worker *types.Worker,
|
||||||
pendingHeaders: make(map[uint32]interface{}),
|
pendingHeaders: make(map[uint32]interface{}),
|
||||||
worker: worker,
|
worker: worker,
|
||||||
|
|
||||||
triggerNewEmail: triggerNewEmail,
|
triggerNewEmail: triggerNewEmail,
|
||||||
|
triggerDirectoryChange: triggerDirectoryChange,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +150,7 @@ func merge(to *models.MessageInfo, from *models.MessageInfo) {
|
||||||
|
|
||||||
func (store *MessageStore) Update(msg types.WorkerMessage) {
|
func (store *MessageStore) Update(msg types.WorkerMessage) {
|
||||||
update := false
|
update := false
|
||||||
|
directoryChange := false
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case *types.DirectoryInfo:
|
case *types.DirectoryInfo:
|
||||||
store.DirInfo = *msg.Info
|
store.DirInfo = *msg.Info
|
||||||
|
@ -159,6 +163,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
|
||||||
newMap[uid] = msg
|
newMap[uid] = msg
|
||||||
} else {
|
} else {
|
||||||
newMap[uid] = nil
|
newMap[uid] = nil
|
||||||
|
directoryChange = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
store.Messages = newMap
|
store.Messages = newMap
|
||||||
|
@ -225,6 +230,10 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
|
||||||
if update {
|
if update {
|
||||||
store.update()
|
store.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if directoryChange && store.triggerDirectoryChange != nil {
|
||||||
|
store.triggerDirectoryChange()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *MessageStore) OnUpdate(fn func(store *MessageStore)) {
|
func (store *MessageStore) OnUpdate(fn func(store *MessageStore)) {
|
||||||
|
|
|
@ -23,6 +23,10 @@ type Interactive interface {
|
||||||
Focus(focus bool)
|
Focus(focus bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Beeper interface {
|
||||||
|
OnBeep(func() error)
|
||||||
|
}
|
||||||
|
|
||||||
type Simulator interface {
|
type Simulator interface {
|
||||||
// Queues up the given input events for simulation
|
// Queues up the given input events for simulation
|
||||||
Simulate(events []tcell.Event)
|
Simulate(events []tcell.Event)
|
||||||
|
@ -33,6 +37,11 @@ type DrawableInteractive interface {
|
||||||
Interactive
|
Interactive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DrawableInteractiveBeeper interface {
|
||||||
|
DrawableInteractive
|
||||||
|
Beeper
|
||||||
|
}
|
||||||
|
|
||||||
// A drawable which contains other drawables
|
// A drawable which contains other drawables
|
||||||
type Container interface {
|
type Container interface {
|
||||||
Drawable
|
Drawable
|
||||||
|
|
|
@ -19,7 +19,7 @@ type UI struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Initialize(conf *config.AercConfig,
|
func Initialize(conf *config.AercConfig,
|
||||||
content DrawableInteractive) (*UI, error) {
|
content DrawableInteractiveBeeper) (*UI, error) {
|
||||||
|
|
||||||
screen, err := tcell.NewScreen()
|
screen, err := tcell.NewScreen()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -57,6 +57,7 @@ func Initialize(conf *config.AercConfig,
|
||||||
content.OnInvalidate(func(_ Drawable) {
|
content.OnInvalidate(func(_ Drawable) {
|
||||||
atomic.StoreInt32(&state.invalid, 1)
|
atomic.StoreInt32(&state.invalid, 1)
|
||||||
})
|
})
|
||||||
|
content.OnBeep(screen.Beep)
|
||||||
content.Focus(true)
|
content.Focus(true)
|
||||||
|
|
||||||
return &state, nil
|
return &state, nil
|
||||||
|
|
|
@ -205,6 +205,10 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
|
||||||
func(msg *models.MessageInfo) {
|
func(msg *models.MessageInfo) {
|
||||||
acct.conf.Triggers.ExecNewEmail(acct.acct,
|
acct.conf.Triggers.ExecNewEmail(acct.acct,
|
||||||
acct.conf, msg)
|
acct.conf, msg)
|
||||||
|
}, func() {
|
||||||
|
if acct.conf.Ui.NewMessageBell {
|
||||||
|
acct.host.Beep()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
acct.dirlist.SetMsgStore(msg.Info.Name, store)
|
acct.dirlist.SetMsgStore(msg.Info.Name, store)
|
||||||
store.OnUpdate(func(_ *lib.MessageStore) {
|
store.OnUpdate(func(_ *lib.MessageStore) {
|
||||||
|
|
|
@ -30,6 +30,7 @@ type Aerc struct {
|
||||||
statusline *StatusLine
|
statusline *StatusLine
|
||||||
pendingKeys []config.KeyStroke
|
pendingKeys []config.KeyStroke
|
||||||
tabs *libui.Tabs
|
tabs *libui.Tabs
|
||||||
|
beep func() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAerc(conf *config.AercConfig, logger *log.Logger,
|
func NewAerc(conf *config.AercConfig, logger *log.Logger,
|
||||||
|
@ -84,6 +85,20 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger,
|
||||||
return aerc
|
return aerc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (aerc *Aerc) OnBeep(f func() error) {
|
||||||
|
aerc.beep = f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aerc *Aerc) Beep() {
|
||||||
|
if aerc.beep == nil {
|
||||||
|
aerc.logger.Printf("should beep, but no beeper")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := aerc.beep(); err != nil {
|
||||||
|
aerc.logger.Printf("tried to beep, but could not: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (aerc *Aerc) Tick() bool {
|
func (aerc *Aerc) Tick() bool {
|
||||||
more := false
|
more := false
|
||||||
for _, acct := range aerc.accounts {
|
for _, acct := range aerc.accounts {
|
||||||
|
|
|
@ -8,4 +8,5 @@ type TabHost interface {
|
||||||
BeginExCommand()
|
BeginExCommand()
|
||||||
SetStatus(status string) *StatusMessage
|
SetStatus(status string) *StatusMessage
|
||||||
PushStatus(text string, expiry time.Duration) *StatusMessage
|
PushStatus(text string, expiry time.Duration) *StatusMessage
|
||||||
|
Beep()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue