add tui
This commit is contained in:
parent
25eef75018
commit
f1c08e5a36
8 changed files with 337 additions and 23 deletions
274
cmd/ecload-tui/main.go
Normal file
274
cmd/ecload-tui/main.go
Normal file
|
@ -0,0 +1,274 @@
|
|||
/* 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"
|
||||
)
|
||||
|
||||
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()
|
||||
}
|
|
@ -5,9 +5,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/jawher/mow.cli"
|
||||
|
@ -15,23 +13,8 @@ import (
|
|||
"ecload/pkg/ecload"
|
||||
)
|
||||
|
||||
// Initialize logger formats.
|
||||
func initLogger(
|
||||
traceHandle io.Writer,
|
||||
infoHandle io.Writer,
|
||||
warningHandle io.Writer,
|
||||
errorHandle io.Writer) ecload.Logger {
|
||||
|
||||
return ecload.Logger{
|
||||
Trace: log.New(traceHandle, "TRACE: ", log.Ldate|log.Ltime),
|
||||
Info: log.New(infoHandle, "INFO: ", log.Ldate|log.Ltime),
|
||||
Warning: log.New(warningHandle, "WARNING: ", log.Ldate|log.Ltime),
|
||||
Error: log.New(errorHandle, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
logger := initLogger(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
|
||||
logger := ecload.InitLogger(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
|
||||
|
||||
app := cli.App("ecload", "Download books from https://www.e-codices.unifr.ch")
|
||||
app.Version("v version", "0.1.0")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue