parent
2ccc92179b
commit
50114764a7
8
Gopkg.lock
generated
8
Gopkg.lock
generated
@ -1,6 +1,12 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/0xAX/notificator"
|
||||
packages = ["."]
|
||||
revision = "88d57ee9043ba88d6a62e437fa15dda1ca0d2b59"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/erroneousboat/termui"
|
||||
packages = ["."]
|
||||
@ -50,6 +56,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "353a2a71e00ecf8dd6123a02828c450fa6d38472a98792d2d8a4cd6349900f11"
|
||||
inputs-digest = "6cdfd0125aad6371a6f4e75c7fc29507cee4a6001a6c68e06c7237066a31153a"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
@ -1,4 +1,4 @@
|
||||
Slack-Term
|
||||
slack-term
|
||||
==========
|
||||
|
||||
A [Slack](https://slack.com) client for your terminal.
|
||||
@ -42,7 +42,11 @@ Setup
|
||||
"slack_token": "yourslacktokenhere",
|
||||
|
||||
// OPTIONAL: set the width of the sidebar (between 1 and 11), default is 1
|
||||
"sidebar_width": 3,
|
||||
"sidebar_width": 1,
|
||||
|
||||
// OPTIONAL: turn on desktop notifications for all incoming messages,
|
||||
default is false
|
||||
"notify": false,
|
||||
|
||||
// OPTIONAL: define custom key mappings, defaults are:
|
||||
"key_map": {
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
// Config is the definition of a Config struct
|
||||
type Config struct {
|
||||
SlackToken string `json:"slack_token"`
|
||||
Notify bool `json:"notify"`
|
||||
SidebarWidth int `json:"sidebar_width"`
|
||||
MainWidth int `json:"-"`
|
||||
KeyMap map[string]keyMapping `json:"key_map"`
|
||||
@ -59,6 +60,7 @@ func getDefaultConfig() Config {
|
||||
return Config{
|
||||
SidebarWidth: 1,
|
||||
MainWidth: 11,
|
||||
Notify: true,
|
||||
KeyMap: map[string]keyMapping{
|
||||
"command": {
|
||||
"i": "mode-insert",
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
|
||||
"github.com/0xAX/notificator"
|
||||
"github.com/erroneousboat/termui"
|
||||
termbox "github.com/nsf/termbox-go"
|
||||
|
||||
@ -26,6 +27,7 @@ type AppContext struct {
|
||||
Config *config.Config
|
||||
Debug bool
|
||||
Mode string
|
||||
Notify *notificator.Notificator
|
||||
}
|
||||
|
||||
// CreateAppContext creates an application context which can be passed
|
||||
@ -92,5 +94,6 @@ func CreateAppContext(flgConfig string, flgDebug bool) (*AppContext, error) {
|
||||
Config: config,
|
||||
Debug: flgDebug,
|
||||
Mode: CommandMode,
|
||||
Notify: notificator.New(notificator.Options{AppName: "slack-term"}),
|
||||
}, nil
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/0xAX/notificator"
|
||||
"github.com/erroneousboat/termui"
|
||||
"github.com/nlopes/slack"
|
||||
termbox "github.com/nsf/termbox-go"
|
||||
@ -14,7 +15,8 @@ import (
|
||||
"github.com/erroneousboat/slack-term/views"
|
||||
)
|
||||
|
||||
var timer *time.Timer
|
||||
var scrollTimer *time.Timer
|
||||
var notifyTimer *time.Timer
|
||||
|
||||
// actionMap binds specific action names to the function counterparts,
|
||||
// these action names can then be used to bind them to specific keys
|
||||
@ -114,7 +116,7 @@ func messageHandler(ctx *context.AppContext) {
|
||||
// Add message to the selected channel
|
||||
if ev.Channel == ctx.Service.Channels[ctx.View.Channels.SelectedChannel].ID {
|
||||
|
||||
// reverse order of messages, mainly done
|
||||
// Reverse order of messages, mainly done
|
||||
// when attachments are added to message
|
||||
for i := len(msg) - 1; i >= 0; i-- {
|
||||
ctx.View.Chat.AddMessage(
|
||||
@ -252,12 +254,12 @@ func actionSearch(ctx *context.AppContext, key rune) {
|
||||
actionInput(ctx.View, key)
|
||||
|
||||
go func() {
|
||||
if timer != nil {
|
||||
timer.Stop()
|
||||
if scrollTimer != nil {
|
||||
scrollTimer.Stop()
|
||||
}
|
||||
|
||||
timer = time.NewTimer(time.Second / 4)
|
||||
<-timer.C
|
||||
scrollTimer = time.NewTimer(time.Second / 4)
|
||||
<-scrollTimer.C
|
||||
|
||||
// Only actually search when the time expires
|
||||
term := ctx.View.Input.GetText()
|
||||
@ -311,15 +313,15 @@ func actionGetMessages(ctx *context.AppContext) {
|
||||
// the list without executing the actionChangeChannel event
|
||||
func actionMoveCursorUpChannels(ctx *context.AppContext) {
|
||||
go func() {
|
||||
if timer != nil {
|
||||
timer.Stop()
|
||||
if scrollTimer != nil {
|
||||
scrollTimer.Stop()
|
||||
}
|
||||
|
||||
ctx.View.Channels.MoveCursorUp()
|
||||
termui.Render(ctx.View.Channels)
|
||||
|
||||
timer = time.NewTimer(time.Second / 4)
|
||||
<-timer.C
|
||||
scrollTimer = time.NewTimer(time.Second / 4)
|
||||
<-scrollTimer.C
|
||||
|
||||
// Only actually change channel when the timer expires
|
||||
actionChangeChannel(ctx)
|
||||
@ -331,15 +333,15 @@ func actionMoveCursorUpChannels(ctx *context.AppContext) {
|
||||
// the list without executing the actionChangeChannel event
|
||||
func actionMoveCursorDownChannels(ctx *context.AppContext) {
|
||||
go func() {
|
||||
if timer != nil {
|
||||
timer.Stop()
|
||||
if scrollTimer != nil {
|
||||
scrollTimer.Stop()
|
||||
}
|
||||
|
||||
ctx.View.Channels.MoveCursorDown()
|
||||
termui.Render(ctx.View.Channels)
|
||||
|
||||
timer = time.NewTimer(time.Second / 4)
|
||||
<-timer.C
|
||||
scrollTimer = time.NewTimer(time.Second / 4)
|
||||
<-scrollTimer.C
|
||||
|
||||
// Only actually change channel when the timer expires
|
||||
actionChangeChannel(ctx)
|
||||
@ -402,7 +404,28 @@ func actionNewMessage(ctx *context.AppContext, channelID string) {
|
||||
ctx.Service.MarkAsUnread(channelID)
|
||||
ctx.View.Channels.SetChannels(ctx.Service.ChannelsToString())
|
||||
termui.Render(ctx.View.Channels)
|
||||
|
||||
// Terminal bell
|
||||
fmt.Print("\a")
|
||||
|
||||
// Desktop notification
|
||||
if ctx.Config.Notify {
|
||||
go func() {
|
||||
if notifyTimer != nil {
|
||||
notifyTimer.Stop()
|
||||
}
|
||||
|
||||
notifyTimer = time.NewTimer(time.Second * 2)
|
||||
<-notifyTimer.C
|
||||
|
||||
// Only actually notify when time expires
|
||||
ctx.Notify.Push(
|
||||
"slack-term",
|
||||
ctx.Service.CreateNotifyMessage(channelID), "",
|
||||
notificator.UR_NORMAL,
|
||||
)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func actionSetPresence(ctx *context.AppContext, channelID string, presence string) {
|
||||
|
@ -306,8 +306,9 @@ func (s *SlackService) MarkAsRead(channelID int) {
|
||||
}
|
||||
}
|
||||
|
||||
// MarkAsUnread will set the channel as unread
|
||||
func (s *SlackService) MarkAsUnread(channelID string) {
|
||||
// FindChannel will loop over s.Channels to find the index where the
|
||||
// channelID equals the ID
|
||||
func (s *SlackService) FindChannel(channelID string) int {
|
||||
var index int
|
||||
for i, channel := range s.Channels {
|
||||
if channel.ID == channelID {
|
||||
@ -315,9 +316,21 @@ func (s *SlackService) MarkAsUnread(channelID string) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// MarkAsUnread will set the channel as unread
|
||||
func (s *SlackService) MarkAsUnread(channelID string) {
|
||||
index := s.FindChannel(channelID)
|
||||
s.Channels[index].Notification = true
|
||||
}
|
||||
|
||||
// GetChannelName will return the name for a specific channelID
|
||||
func (s *SlackService) GetChannelName(channelID string) string {
|
||||
index := s.FindChannel(channelID)
|
||||
return s.Channels[index].Name
|
||||
}
|
||||
|
||||
// SendMessage will send a message to a particular channel
|
||||
func (s *SlackService) SendMessage(channelID int, message string) {
|
||||
|
||||
@ -519,6 +532,21 @@ func (s *SlackService) CreateMessageFromMessageEvent(message *slack.MessageEvent
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
func (s *SlackService) CreateNotifyMessage(channelID string) string {
|
||||
channel := s.Channels[s.FindChannel(channelID)]
|
||||
|
||||
switch channel.Type {
|
||||
case ChannelTypeChannel:
|
||||
return fmt.Sprintf("Message received on channel: %s", channel.Name)
|
||||
case ChannelTypeGroup:
|
||||
return fmt.Sprintf("Message received in group: %s", channel.Name)
|
||||
case ChannelTypeIM:
|
||||
return fmt.Sprintf("Message received from: %s", channel.Name)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// parseMessage will parse a message string and find and replace:
|
||||
// - emoji's
|
||||
// - mentions
|
||||
|
25
vendor/github.com/0xAX/notificator/.gitignore
generated
vendored
Normal file
25
vendor/github.com/0xAX/notificator/.gitignore
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
|
||||
.idea
|
27
vendor/github.com/0xAX/notificator/LICENSE
generated
vendored
Normal file
27
vendor/github.com/0xAX/notificator/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2014, 0xAX
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the {organization} nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
49
vendor/github.com/0xAX/notificator/README.md
generated
vendored
Normal file
49
vendor/github.com/0xAX/notificator/README.md
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
notificator
|
||||
===========================
|
||||
|
||||
Desktop notification with Golang for:
|
||||
|
||||
* Windows with `growlnotify`;
|
||||
* Mac OS X with `terminal-notifier` (if installed) or `osascript` (native, 10.9 Mavericks or Up.);
|
||||
* Linux with `notify-send` for Gnome and `kdialog` for Kde.
|
||||
|
||||
Usage
|
||||
------
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/0xAX/notificator"
|
||||
)
|
||||
|
||||
var notify *notificator.Notificator
|
||||
|
||||
func main() {
|
||||
|
||||
notify = notificator.New(notificator.Options{
|
||||
DefaultIcon: "icon/default.png",
|
||||
AppName: "My test App",
|
||||
})
|
||||
|
||||
notify.Push("title", "text", "/home/user/icon.png", notificator.UR_CRITICAL)
|
||||
}
|
||||
```
|
||||
|
||||
TODO
|
||||
-----
|
||||
|
||||
* Add more options for different notificators.
|
||||
|
||||
Сontribution
|
||||
------------
|
||||
|
||||
* Fork;
|
||||
* Make changes;
|
||||
* Send pull request;
|
||||
* Thank you.
|
||||
|
||||
author
|
||||
----------
|
||||
|
||||
[@0xAX](https://twitter.com/0xAX)
|
166
vendor/github.com/0xAX/notificator/notification.go
generated
vendored
Normal file
166
vendor/github.com/0xAX/notificator/notification.go
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
package notificator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
DefaultIcon string
|
||||
AppName string
|
||||
}
|
||||
|
||||
const (
|
||||
UR_NORMAL = "normal"
|
||||
UR_CRITICAL = "critical"
|
||||
)
|
||||
|
||||
type notifier interface {
|
||||
push(title string, text string, iconPath string) *exec.Cmd
|
||||
pushCritical(title string, text string, iconPath string) *exec.Cmd
|
||||
}
|
||||
|
||||
type Notificator struct {
|
||||
notifier notifier
|
||||
defaultIcon string
|
||||
}
|
||||
|
||||
func (n Notificator) Push(title string, text string, iconPath string, urgency string) error {
|
||||
icon := n.defaultIcon
|
||||
|
||||
if iconPath != "" {
|
||||
icon = iconPath
|
||||
}
|
||||
|
||||
if urgency == UR_CRITICAL {
|
||||
return n.notifier.pushCritical(title, text, icon).Run()
|
||||
}
|
||||
|
||||
return n.notifier.push(title, text, icon).Run()
|
||||
|
||||
}
|
||||
|
||||
type osxNotificator struct {
|
||||
AppName string
|
||||
}
|
||||
|
||||
func (o osxNotificator) push(title string, text string, iconPath string) *exec.Cmd {
|
||||
|
||||
// Checks if terminal-notifier exists, and is accessible.
|
||||
|
||||
term_notif := CheckTermNotif()
|
||||
os_version_check := CheckMacOSVersion()
|
||||
|
||||
// if terminal-notifier exists, use it.
|
||||
// else, fall back to osascript. (Mavericks and later.)
|
||||
|
||||
if term_notif == true {
|
||||
return exec.Command("terminal-notifier", "-title", o.AppName, "-message", text, "-subtitle", title, "-appIcon", iconPath)
|
||||
} else if os_version_check == true {
|
||||
title = strings.Replace(title, `"`, `\"`, -1)
|
||||
text = strings.Replace(text, `"`, `\"`, -1)
|
||||
|
||||
notification := fmt.Sprintf("display notification \"%s\" with title \"%s\" subtitle \"%s\"", text, o.AppName, title)
|
||||
return exec.Command("osascript", "-e", notification)
|
||||
}
|
||||
|
||||
// finally falls back to growlnotify.
|
||||
|
||||
return exec.Command("growlnotify", "-n", o.AppName, "--image", iconPath, "-m", title)
|
||||
}
|
||||
|
||||
// Causes the notification to stick around until clicked.
|
||||
func (o osxNotificator) pushCritical(title string, text string, iconPath string) *exec.Cmd {
|
||||
|
||||
// same function as above...
|
||||
|
||||
term_notif := CheckTermNotif()
|
||||
os_version_check := CheckMacOSVersion()
|
||||
|
||||
if term_notif == true {
|
||||
// timeout set to 30 seconds, to show the importance of the notification
|
||||
return exec.Command("terminal-notifier", "-title", o.AppName, "-message", text, "-subtitle", title, "-timeout", "30")
|
||||
} else if os_version_check == true {
|
||||
notification := fmt.Sprintf("display notification \"%s\" with title \"%s\" subtitle \"%s\"", text, o.AppName, title)
|
||||
return exec.Command("osascript", "-e", notification)
|
||||
}
|
||||
|
||||
return exec.Command("growlnotify", "-n", o.AppName, "--image", iconPath, "-m", title)
|
||||
|
||||
}
|
||||
|
||||
type linuxNotificator struct{}
|
||||
|
||||
func (l linuxNotificator) push(title string, text string, iconPath string) *exec.Cmd {
|
||||
return exec.Command("notify-send", "-i", iconPath, title, text)
|
||||
}
|
||||
|
||||
// Causes the notification to stick around until clicked.
|
||||
func (l linuxNotificator) pushCritical(title string, text string, iconPath string) *exec.Cmd {
|
||||
return exec.Command("notify-send", "-i", iconPath, title, text, "-u", "critical")
|
||||
}
|
||||
|
||||
type windowsNotificator struct{}
|
||||
|
||||
func (w windowsNotificator) push(title string, text string, iconPath string) *exec.Cmd {
|
||||
return exec.Command("growlnotify", "/i:", iconPath, "/t:", title, text)
|
||||
}
|
||||
|
||||
// Causes the notification to stick around until clicked.
|
||||
func (w windowsNotificator) pushCritical(title string, text string, iconPath string) *exec.Cmd {
|
||||
return exec.Command("notify-send", "-i", iconPath, title, text, "/s", "true", "/p", "2")
|
||||
}
|
||||
|
||||
func New(o Options) *Notificator {
|
||||
|
||||
var Notifier notifier
|
||||
|
||||
switch runtime.GOOS {
|
||||
|
||||
case "darwin":
|
||||
Notifier = osxNotificator{AppName: o.AppName}
|
||||
case "linux":
|
||||
Notifier = linuxNotificator{}
|
||||
case "windows":
|
||||
Notifier = windowsNotificator{}
|
||||
|
||||
}
|
||||
|
||||
return &Notificator{notifier: Notifier, defaultIcon: o.DefaultIcon}
|
||||
}
|
||||
|
||||
// Helper function for macOS
|
||||
|
||||
func CheckTermNotif() bool {
|
||||
// Checks if terminal-notifier exists, and is accessible.
|
||||
if err := exec.Command("which", "terminal-notifier").Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
// no error, so return true. (terminal-notifier exists)
|
||||
return true
|
||||
}
|
||||
|
||||
func CheckMacOSVersion() bool {
|
||||
// Checks if the version of macOS is 10.9 or Higher (osascript support for notifications.)
|
||||
|
||||
cmd := exec.Command("sw_vers", "-productVersion")
|
||||
check, _ := cmd.Output()
|
||||
|
||||
version := strings.Split(strings.TrimSpace(string(check)), ".")
|
||||
|
||||
// semantic versioning of macOS
|
||||
|
||||
major, _ := strconv.Atoi(version[0])
|
||||
minor, _ := strconv.Atoi(version[1])
|
||||
|
||||
if major < 10 {
|
||||
return false
|
||||
} else if major == 10 && minor < 9 {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user