summaryrefslogtreecommitdiffstats
path: root/pkg/gui/app_status_manager.go
blob: e625fcad2dcc3e2252b9ea70c8bbd1775fa12f4a (plain)
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
package gui

import (
	"sync"
	"time"

	"github.com/jesseduffield/lazygit/pkg/utils"
)

type appStatus struct {
	message    string
	statusType string
	id         int
}

type statusManager struct {
	statuses []appStatus
	nextId   int
	mutex    sync.Mutex
}

func (m *statusManager) removeStatus(id int) {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	newStatuses := []appStatus{}
	for _, status := range m.statuses {
		if status.id != id {
			newStatuses = append(newStatuses, status)
		}
	}
	m.statuses = newStatuses
}

func (m *statusManager) addWaitingStatus(message string) int {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	m.nextId += 1
	id := m.nextId

	newStatus := appStatus{
		message:    message,
		statusType: "waiting",
		id:         id,
	}
	m.statuses = append([]appStatus{newStatus}, m.statuses...)

	return id
}

func (m *statusManager) addToastStatus(message string) int {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	m.nextId++
	id := m.nextId

	newStatus := appStatus{
		message:    message,
		statusType: "toast",
		id:         id,
	}
	m.statuses = append([]appStatus{newStatus}, m.statuses...)

	go func() {
		time.Sleep(time.Second * 2)

		m.removeStatus(id)
	}()

	return id
}

func (m *statusManager) getStatusString() string {
	if len(m.statuses) == 0 {
		return ""
	}
	topStatus := m.statuses[0]
	if topStatus.statusType == "waiting" {
		return topStatus.message + " " + utils.Loader()
	}
	return topStatus.message
}

func (gui *Gui) raiseToast(message string) {
	gui.statusManager.addToastStatus(message)

	gui.renderAppStatus()
}

func (gui *Gui) renderAppStatus() {
	go utils.Safe(func() {
		ticker := time.NewTicker(time.Millisecond * 50)
		defer ticker.Stop()
		for range ticker.C {
			appStatus := gui.statusManager.getStatusString()
			gui.OnUIThread(func() error {
				return gui.renderString(gui.Views.AppStatus, appStatus)
			})

			if appStatus == "" {
				return
			}
		}
	})
}

// WithWaitingStatus wraps a function and shows a waiting status while the function is still executing
func (gui *Gui) WithWaitingStatus(message string, f func() error) error {
	go utils.Safe(func() {
		id := gui.statusManager.addWaitingStatus(message)

		defer func() {
			gui.statusManager.removeStatus(id)
		}()

		gui.renderAppStatus()

		if err := f(); err != nil {
			gui.OnUIThread(func() error {
				return gui.surfaceError(err)
			})
		}
	})

	return nil
}