-
Notifications
You must be signed in to change notification settings - Fork 65
/
toast.go
135 lines (119 loc) · 3.97 KB
/
toast.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package go_toast
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"text/template"
"github.com/nu7hatch/gouuid"
)
var toastTemplate *template.Template
func init() {
toastTemplate = template.New("toast")
toastTemplate.Parse(`
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
$APP_ID = '{{if .AppID}}{{.AppID}}{{else}}io.github.jacobmarshall.go-toast{{end}}'
$template = @"
<toast>
<visual>
<binding template="ToastGeneric">
{{if .Icon}}
<image placement="appLogoOverride" src="{{.Icon}}" />
{{end}}
{{if .Title}}
<text>{{.Title}}</text>
{{end}}
{{if .Message}}
<text>{{.Message}}</text>
{{end}}
</binding>
</visual>
{{if .Actions}}
<actions>
{{range .Actions}}
<action activationType="{{.Type}}" content="{{.Label}}" arguments="{{.Arguments}}" />
{{end}}
</actions>
{{end}}
</toast>
"@
$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
$xml.LoadXml($template)
$toast = New-Object Windows.UI.Notifications.ToastNotification $xml
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($APP_ID).Show($toast)
`)
}
type Notification struct {
// The name of your app. This value shows up in Windows 10's Action Centre, so make it
// something readable for your users. It can contain spaces, however special characters
// (eg. é) are not supported.
AppID string
// The main title/heading for the toast notification.
Title string
// The single/multi line message to display for the toast notification.
Message string
// An optional path to an image on the OS to display to the left of the title & message.
Icon string
// Optional action buttons to display below the notification title & message.
Actions []Action
}
// Defines an actionable button.
// See https://msdn.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-adaptive-interactive-toasts for more info.
//
// Only protocol type action buttons are actually useful, as there's no way of receiving feedback from the
// user's choice. Examples of protocol type action buttons include: "bingmaps:?q=sushi" to open up Windows 10's
// maps app with a pre-populated search field set to "sushi".
//
// toast.Action{"protocol", "Open Maps", "bingmaps:?q=sushi"}
type Action struct {
Type string
Label string
Arguments string
}
func (n *Notification) buildXML() (string, error) {
var out bytes.Buffer
err := toastTemplate.Execute(&out, n)
if err != nil {
return "", err
}
return out.String(), nil
}
// Builds the Windows PowerShell script & invokes it, causing the toast to display.
//
// Note: Running the PowerShell script is by far the slowest process here, and can take a few
// seconds in some cases.
//
// notification := toast.Notification{
// AppID: "Example App",
// Title: "My notification",
// Message: "Some message about how important something is...",
// Icon: "go.png",
// Actions: []toast.Action{
// {"protocol", "I'm a button", ""},
// {"protocol", "Me too!", ""},
// },
// }
// err := notification.Push()
// if err != nil {
// log.Fatalln(err)
// }
func (n *Notification) Push() error {
xml, _ := n.buildXML()
return invokeTemporaryScript(xml)
}
func invokeTemporaryScript(content string) error {
id, _ := uuid.NewV4()
file := filepath.Join(os.TempDir(), id.String()+".ps1")
defer os.Remove(file)
err := ioutil.WriteFile(file, []byte(content), 0600)
if err != nil {
return err
}
if err = exec.Command("PowerShell", "-ExecutionPolicy", "Bypass", "-File", file).Run(); err != nil {
return err
}
return nil
}