225 lines
5.2 KiB
Go
225 lines
5.2 KiB
Go
package scenes
|
|
|
|
import (
|
|
"github.com/charmbracelet/bubbles/progress"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
|
|
"github.com/satisfactorymodding/ficsit-cli/cli"
|
|
"github.com/satisfactorymodding/ficsit-cli/tea/components"
|
|
"github.com/satisfactorymodding/ficsit-cli/tea/utils"
|
|
)
|
|
|
|
var _ tea.Model = (*apply)(nil)
|
|
|
|
type update struct {
|
|
installName string
|
|
modName string
|
|
completed []string
|
|
installTotal int
|
|
installCurrent int
|
|
modTotal int
|
|
modCurrent int
|
|
done bool
|
|
}
|
|
|
|
type apply struct {
|
|
root components.RootModel
|
|
parent tea.Model
|
|
error *components.ErrorComponent
|
|
updateChannel chan update
|
|
errorChannel chan error
|
|
cancelChannel chan bool
|
|
title string
|
|
status update
|
|
overall progress.Model
|
|
sub progress.Model
|
|
cancelled bool
|
|
}
|
|
|
|
func NewApply(root components.RootModel, parent tea.Model) tea.Model {
|
|
overall := progress.New(progress.WithSolidFill("118"))
|
|
sub := progress.New(progress.WithSolidFill("202"))
|
|
|
|
updateChannel := make(chan update)
|
|
errorChannel := make(chan error)
|
|
cancelChannel := make(chan bool, 1)
|
|
|
|
model := &apply{
|
|
root: root,
|
|
parent: parent,
|
|
title: utils.NonListTitleStyle.MarginTop(1).MarginBottom(1).Render("Applying Changes"),
|
|
overall: overall,
|
|
sub: sub,
|
|
status: update{
|
|
completed: []string{},
|
|
|
|
installName: "",
|
|
installTotal: 100,
|
|
installCurrent: 0,
|
|
|
|
modName: "",
|
|
modTotal: 100,
|
|
modCurrent: 0,
|
|
|
|
done: false,
|
|
},
|
|
updateChannel: updateChannel,
|
|
errorChannel: errorChannel,
|
|
cancelChannel: cancelChannel,
|
|
cancelled: false,
|
|
}
|
|
|
|
go func() {
|
|
result := &update{
|
|
completed: make([]string, 0),
|
|
|
|
installName: "",
|
|
installTotal: 100,
|
|
installCurrent: 0,
|
|
|
|
modName: "",
|
|
modTotal: 100,
|
|
modCurrent: 0,
|
|
|
|
done: false,
|
|
}
|
|
updateChannel <- *result
|
|
|
|
for _, installation := range root.GetGlobal().Installations.Installations {
|
|
result.installName = installation.Path
|
|
updateChannel <- *result
|
|
|
|
installChannel := make(chan cli.InstallUpdate)
|
|
|
|
go func() {
|
|
for data := range installChannel {
|
|
result.installName = installation.Path
|
|
result.installCurrent = int(data.OverallProgress * 100)
|
|
|
|
if data.DownloadProgress < 1 {
|
|
result.modName = "Downloading: " + data.ModName
|
|
result.modCurrent = int(data.DownloadProgress * 100)
|
|
} else {
|
|
result.modName = "Extracting: " + data.ModName
|
|
result.modCurrent = int(data.ExtractProgress * 100)
|
|
}
|
|
|
|
updateChannel <- *result
|
|
}
|
|
}()
|
|
|
|
if err := installation.Install(root.GetGlobal(), installChannel); err != nil {
|
|
errorChannel <- err
|
|
return
|
|
}
|
|
|
|
close(installChannel)
|
|
|
|
result.modName = ""
|
|
result.installTotal = 100
|
|
result.completed = append(result.completed, installation.Path)
|
|
updateChannel <- *result
|
|
|
|
stop := false
|
|
select {
|
|
case <-cancelChannel:
|
|
stop = true
|
|
default:
|
|
}
|
|
|
|
if stop {
|
|
break
|
|
}
|
|
}
|
|
|
|
result.done = true
|
|
result.installName = ""
|
|
updateChannel <- *result
|
|
}()
|
|
|
|
return model
|
|
}
|
|
|
|
func (m apply) Init() tea.Cmd {
|
|
return utils.Ticker()
|
|
}
|
|
|
|
func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
switch keypress := msg.String(); keypress {
|
|
case KeyControlC:
|
|
return m, tea.Quit
|
|
case KeyEscape:
|
|
m.cancelled = true
|
|
m.cancelChannel <- true
|
|
return m, nil
|
|
case KeyEnter:
|
|
if m.status.done {
|
|
if m.parent != nil {
|
|
return m.parent, m.parent.Init()
|
|
}
|
|
}
|
|
return m, nil
|
|
}
|
|
case tea.WindowSizeMsg:
|
|
m.root.SetSize(msg)
|
|
case components.ErrorComponentTimeoutMsg:
|
|
m.error = nil
|
|
case utils.TickMsg:
|
|
select {
|
|
case newStatus := <-m.updateChannel:
|
|
m.status = newStatus
|
|
break
|
|
case err := <-m.errorChannel:
|
|
errorComponent, _ := components.NewErrorComponent(err.Error(), 0)
|
|
m.error = errorComponent
|
|
break
|
|
default:
|
|
// Skip if nothing there
|
|
break
|
|
}
|
|
return m, utils.Ticker()
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
func (m apply) View() string {
|
|
strs := make([]string, 0)
|
|
for _, s := range m.status.completed {
|
|
strs = append(strs, lipgloss.NewStyle().Foreground(lipgloss.Color("22")).Render("✓ ")+s)
|
|
}
|
|
|
|
if m.status.installName != "" {
|
|
marginTop := 0
|
|
if len(m.status.completed) > 0 {
|
|
marginTop = 1
|
|
}
|
|
|
|
strs = append(strs, lipgloss.NewStyle().MarginTop(marginTop).Render(m.status.installName))
|
|
strs = append(strs, m.overall.ViewAs(float64(m.status.installCurrent)/float64(m.status.installTotal)))
|
|
}
|
|
|
|
if m.status.modName != "" {
|
|
strs = append(strs, lipgloss.NewStyle().MarginTop(1).Render(m.status.modName))
|
|
strs = append(strs, m.sub.ViewAs(float64(m.status.modCurrent)/float64(m.status.modTotal)))
|
|
}
|
|
|
|
if m.status.done {
|
|
if m.cancelled {
|
|
strs = append(strs, utils.LabelStyle.Copy().Foreground(lipgloss.Color("196")).Padding(0).Margin(1).Render("Cancelled! Press Enter to return"))
|
|
} else {
|
|
strs = append(strs, utils.LabelStyle.Copy().Padding(0).Margin(1).Render("Done! Press Enter to return"))
|
|
}
|
|
}
|
|
|
|
result := lipgloss.NewStyle().MarginLeft(1).Render(lipgloss.JoinVertical(lipgloss.Left, strs...))
|
|
|
|
if m.error != nil {
|
|
return lipgloss.JoinVertical(lipgloss.Left, m.title, m.error.View(), result)
|
|
}
|
|
|
|
return lipgloss.JoinVertical(lipgloss.Left, m.title, result)
|
|
}
|