ecload/cmd/ecload-tui/main.go

278 lines
6.9 KiB
Go

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
package main
import (
"encoding/json"
ui "github.com/VladimirMarkelov/clui"
"io/ioutil"
"os"
"path"
"github.com/shibukawa/configdir"
"ecload/pkg/ecload"
)
var Version string
var Build string
const THEME = "//----------------- Theme properties -----------------" +
"//----------------- Colors -----------------" +
"// View colors - internal area and border" +
"ViewBack = white" +
"ViewText = white bold" +
"// general colors" +
"Back = white" +
"Text = black" +
"DisabledText = white" +
"DisabledBack = black bold" +
"// editable & listbox-like controls (interactive ones)" +
"EditBack = blue" +
"EditText = yellow" +
"EditActiveBack = blue bold" +
"EditActiveText = yellow bold" +
"SelectionText = yellow bold" +
"SelectionBack = cyan bold" +
"// scroll control" +
"ScrollText = white bold" +
"ScrollBack = white" +
"ThumbText = white bold" +
"ThumbBack = white" +
"// window-like controls (checkbox, radiogroup...)" +
"ControlText = black" +
"ControlBack = cyan bold" +
"ControlActiveBack = cyan bold" +
"ControlActiveText = yellow bold" +
"ControlDisabledBack = cyan bold" +
"ControlDisabledText = black bold" +
"ControlShadow = black" +
"// progressbar control" +
"ProgressBack = blue" +
"ProgressText = yellow" +
"ProgressActiveBack = blue bold" +
"ProgressActiveText = yellow bold" +
"// button control" +
"ButtonBack=green bold" +
"ButtonText=black" +
"ButtonActiveBack=green bold" +
"ButtonActiveText=white bold" +
"ButtonShadowBack=black" +
"ButtonDisabledText=black bold" +
"ButtonDisabledBack=white" +
"// bar chart control" +
"BarChartBack=black" +
"BarChartText=white" +
"// spark chart" +
"SparkChartBack=black" +
"SparkChartText=white" +
"SparkChartBarBack=black" +
"SparkChartBarText=cyan" +
"SparkChartMaxBack=black" +
"SparkChartMaxText=cyan bold" +
"// table view" +
"TableText=white" +
"TableBack=black" +
"TableSelectedText=white" +
"TableSelectedBack=black bold" +
"TableActiveCellText=white bold" +
"TableActiveCellBack=black bold" +
"TableLineText=white" +
"TableHeaderText=white" +
"TableHeaderBack=black" +
"//----------------- Objects -----------------" +
"SingleBorder=─│┌┐└┘" +
"DoubleBorder=═║╔╗╚╝" +
"Edit=←→V*" +
"ScrollBar=░■▲▼◄►" +
"ViewButtons=^_■[]" +
"CheckBox=[] X?" +
"Radio=() *" +
"ProgressBar=░▒" +
"BarChart=█─│┌┐└┘┬┴├┤┼" +
"SparkChart=█" +
"TableView=─│┼▼▲"
const VENDOR = "vanwa.ch"
const APPNAME = "ecload"
const SETTINGNAME = "last.json"
const WAITWIDTH = 40
const WAITHEIGHT = 10
type settings struct {
Out string
Size int
}
func main() {
logger := ecload.InitLogger(ioutil.Discard, ioutil.Discard, ioutil.Discard, ioutil.Discard)
tmp, err := ioutil.TempDir("", "ecload")
if err != nil {
logger.Error.Println(err)
os.Exit(1)
}
defer os.RemoveAll(tmp)
err = ioutil.WriteFile(path.Join(tmp, "ecload.theme"), []byte(THEME), 0600)
if err != nil {
logger.Error.Println(err)
os.Exit(1)
}
mainLoop(tmp, logger)
}
func createView(themeDir string, logger ecload.Logger) {
configDirs := configdir.New(VENDOR, APPNAME)
cache := configDirs.QueryCacheFolder()
sizes := []string{"small", "medium", "large", "max"}
outPath, _ := os.UserHomeDir()
size := 0
if cache != nil {
var config settings
data, _ := cache.ReadFile(SETTINGNAME)
err := json.Unmarshal(data, &config)
if err == nil {
if config.Out != "" {
outPath = config.Out
}
size = config.Size
}
}
ui.SetThemePath(themeDir)
ui.SetCurrentTheme("ecload")
view := ui.AddWindow(0, 0, 75, 10, "Download e-codices")
view.SetPack(ui.Vertical)
view.SetGaps(0, 1)
view.SetPaddings(2, 2)
view.SetSizable(false)
frmPath := ui.CreateFrame(view, 1, 1, ui.BorderThin, ui.Fixed)
frmPath.SetPack(ui.Vertical)
frmPath.SetTitle("Download path")
lblPath := ui.CreateLabel(frmPath, ui.AutoSize, ui.AutoSize, outPath, ui.Fixed)
btnSet := ui.CreateButton(frmPath, ui.AutoSize, ui.AutoSize, "Select", ui.Fixed)
frmSize := ui.CreateFrame(view, 1, 1, ui.BorderThin, ui.Fixed)
frmSize.SetPack(ui.Vertical)
frmSize.SetTitle("Size")
rg := ui.CreateRadioGroup()
for _, size := range sizes {
radio := ui.CreateRadio(frmSize, ui.AutoSize, size, ui.Fixed)
radio.OnActive(func(active bool) {
go save(lblPath, rg)
})
rg.AddItem(radio)
}
rg.SetSelected(size)
frmId := ui.CreateFrame(view, 1, 1, ui.BorderThin, ui.Fixed)
frmId.SetTitle("Id")
fldId := ui.CreateEditField(frmId, 70, "", ui.Fixed)
frmBtns := ui.CreateFrame(view, 1, 1, ui.BorderNone, ui.Fixed)
frmBtns.SetPack(ui.Vertical)
btnStart := ui.CreateButton(frmBtns, ui.AutoSize, ui.AutoSize, "Download", ui.Fixed)
btnStart.SetEnabled(false)
ui.ActivateControl(view, fldId)
fldId.OnChange(func(ev ui.Event) {
allowStart := fldId.Title() != ""
btnStart.SetEnabled(allowStart)
})
btnSet.OnClick(func(ev ui.Event) {
s := "Select directory"
dlg := ui.CreateFileSelectDialog(
s,
"*",
outPath,
true,
true)
dlg.OnClose(func() {
if dlg.Selected {
lblPath.SetTitle(dlg.FilePath)
go save(lblPath, rg)
}
})
})
btnStart.OnClick(func(ev ui.Event) {
size := sizes[rg.Selected()]
w, h := view.Size()
wait := ui.AddWindow(w / 2 - WAITWIDTH / 2, h / 2 - WAITHEIGHT / 2, WAITWIDTH, WAITHEIGHT, "Downloading...")
wait.SetModal(true)
wait.SetPack(ui.Vertical)
wait.SetGaps(0, 1)
wait.SetPaddings(2, 2)
wait.SetSizable(false)
ui.CreateLabel(wait, ui.AutoSize, ui.AutoSize, "Please be patient. Maybe bring me some tea.", ui.Fixed)
ec := make(chan error)
finished := make(chan bool, 1)
go func(out string, size string, id string, logger ecload.Logger) {
err := ecload.DownloadBook(lblPath.Title(), size, fldId.Title(), logger)
if err != nil {
ec <- err
} else {
close(finished)
}
}(lblPath.Title(), size, fldId.Title(), logger)
select {
case <-finished:
successDlg := ui.CreateAlertDialog("Success", "Download finished.", "Yay!")
successDlg.OnClose(func() {
ui.PutEvent(ui.Event{Type: ui.EventCloseWindow})
ui.ActivateControl(view, fldId)
})
case err := <-ec:
if err != nil {
errorDlg := ui.CreateAlertDialog("Error", err.Error(), "Ah well")
errorDlg.OnClose(func() {
ui.PutEvent(ui.Event{Type: ui.EventCloseWindow})
ui.ActivateControl(view, fldId)
})
}
}
})
}
func save(lblPath *ui.Label, rg *ui.RadioGroup) {
configDirs := configdir.New(VENDOR, APPNAME)
cache := configDirs.QueryCacheFolder()
config := settings { Out: lblPath.Title(), Size: rg.Selected() }
data, _ := json.Marshal(&config)
cache.WriteFile(SETTINGNAME, data)
}
func mainLoop(themeDir string, logger ecload.Logger) {
ui.InitLibrary()
defer ui.DeinitLibrary()
createView(themeDir, logger)
ui.MainLoop()
}