/* 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() }