-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.go
160 lines (136 loc) · 3.47 KB
/
main.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package main
import (
"flag"
"log"
"math/rand"
"os"
"sync"
"time"
"gioman/service"
"gioman/state"
"gioman/view"
mat "gioman/widget/material"
"gioui.org/app"
"gioui.org/font/gofont"
"gioui.org/io/system"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/unit"
"gioui.org/widget/material"
)
var configPath = flag.String("config", "config.json", "a configuration file")
func main() {
flag.Parse()
rand.Seed(time.Now().UnixNano())
if *configPath == "" {
log.Fatalf("-config must be specified")
}
cfg, err := configFromFilepath(*configPath)
if err != nil && !os.IsNotExist(err) {
log.Fatalf("read config: %v", err)
}
var wg sync.WaitGroup
requests := make(chan state.Requests)
wg.Add(1)
go func() {
defer func() {
log.Println("config: request update: done")
wg.Done()
}()
log.Println("config: request update: started")
save := func(cfg *config) {
f, err := os.Create(*configPath)
if err != nil {
// TODO: Show error notification.
log.Printf("config: request update: save: create config: %v", err)
return
}
defer f.Close()
cfg.save(f)
log.Printf("config: request update: save: written %q", *configPath)
}
for r := range requests {
cfg.setRequests(r)
save(&cfg)
}
}()
storage := requestStorage{
requests: cfg.requests(),
save: func(r state.Requests) { requests <- r },
}
go func() {
w := app.NewWindow(app.Size(unit.Dp(1000), unit.Dp(600)))
if err := loop(w, &storage); err != nil {
log.Fatal(err)
}
close(requests)
wg.Wait()
os.Exit(0)
}()
app.Main()
}
func loop(w *app.Window, requests *requestStorage) error {
var (
fetcher service.Fetcher
fetchResponse chan string
)
fetch := func(p service.FetchPayload) {
fetchResponse = make(chan string, 1)
// Ensure closure has its own reference. We need this to guarantee
// the buffer of size 1 will be used once and only once.
fetchResponse := fetchResponse
go func() {
fetchResponse <- fetcher.Fetch(p)
}()
}
th := material.NewTheme(gofont.Collection())
response := "Last response N/A"
appbar := mat.Appbar(th)
home := view.Home(th, fetch, (*homeScreenRequestStorageAdaptor)(requests))
var ops op.Ops
for {
select {
case e := <-w.Events():
switch e := e.(type) {
case system.DestroyEvent:
return e.Err
case system.FrameEvent:
gtx := layout.NewContext(&ops, e)
fetching := fetchResponse != nil
appbar.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return home.Layout(gtx, fetching, response)
})
e.Frame(gtx.Ops)
}
case response = <-fetchResponse:
fetchResponse = nil
}
}
}
// requestStorage and requestProviderAdaptor exist for demonstration purpose.
type requestStorage struct {
requests state.Requests
save func(state.Requests)
}
func (rs *requestStorage) add(m service.Method, url, name string) {
rs.addRequest(state.Request{
Method: m,
URL: url,
Name: name,
})
}
func (rs *requestStorage) addRequest(r state.Request) {
rs.requests = append(rs.requests, r)
rs.save(rs.requests)
}
// homeScreenRequestStorageAdaptor and requestStorage exist for demonstration purpose.
type homeScreenRequestStorageAdaptor requestStorage
func (rp *homeScreenRequestStorageAdaptor) All() state.Requests {
return (*requestStorage)(rp).requests
}
func (rp *homeScreenRequestStorageAdaptor) Save(r state.Request) {
(*requestStorage)(rp).addRequest(r)
}
func (rp *homeScreenRequestStorageAdaptor) At(index int) state.Request {
return (*requestStorage)(rp).requests[index]
}