The very basic client app, not adapted for mobiles.
This commit is contained in:
82
client/internal/services/core/options/dialog.go
Normal file
82
client/internal/services/core/options/dialog.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/lang"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func (o *options) closeOptionsDialog(save bool) {
|
||||
slog.Debug("Closing options dialog.", "save", save)
|
||||
|
||||
if !save {
|
||||
return
|
||||
}
|
||||
|
||||
for _, widget := range o.widgets {
|
||||
if widget.SaveHandler == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := widget.SaveHandler(); err != nil {
|
||||
slog.Error("Failed to save options for module!", "module", widget.Name, "error", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *options) optionsListCreateItem() fyne.CanvasObject {
|
||||
return widget.NewLabel("")
|
||||
}
|
||||
|
||||
func (o *options) optionsListLength() int {
|
||||
return len(o.widgetsItems)
|
||||
}
|
||||
|
||||
func (o *options) optionsListUpdateItem(itemID widget.ListItemID, obj fyne.CanvasObject) {
|
||||
label, _ := obj.(*widget.Label)
|
||||
|
||||
label.SetText(o.widgets[o.widgetsItems[itemID]].Name)
|
||||
}
|
||||
|
||||
func (o *options) ShowOptionsDialog() {
|
||||
optionsWidgetScroll := container.NewScroll(widget.NewLabel(lang.L("options_dialog.select_section")))
|
||||
|
||||
optionsList := widget.NewList(o.optionsListLength, o.optionsListCreateItem, o.optionsListUpdateItem)
|
||||
optionsList.OnSelected = func(listID widget.ListItemID) {
|
||||
// listID должно быть всегда меньше длины, так как является индексом.
|
||||
// Эта проверка отрабатывает, если настроек по какой-то причине нет.
|
||||
if listID >= len(o.widgetsItems) {
|
||||
return
|
||||
}
|
||||
|
||||
optionsWidget := o.widgets[o.widgetsItems[listID]].Widget
|
||||
|
||||
if optionsWidget != nil {
|
||||
optionsWidgetScroll.Content = optionsWidget
|
||||
} else {
|
||||
optionsWidgetScroll.Content = widget.NewLabel(lang.L("options_dialog.no_settings"))
|
||||
}
|
||||
|
||||
optionsWidgetScroll.Refresh()
|
||||
}
|
||||
|
||||
optionsListSplitter := container.NewHSplit(optionsList, optionsWidgetScroll)
|
||||
//nolint:mnd
|
||||
optionsListSplitter.SetOffset(0.25)
|
||||
|
||||
optionsDlg := dialog.NewCustomConfirm(
|
||||
"Options",
|
||||
"Save",
|
||||
"Cancel",
|
||||
optionsListSplitter,
|
||||
o.closeOptionsDialog,
|
||||
o.mainWindow.MainWindow(),
|
||||
)
|
||||
optionsDlg.Resize(o.mainWindow.MainWindow().Canvas().Size())
|
||||
|
||||
optionsDlg.Show()
|
||||
}
|
14
client/internal/services/core/options/dto/option_pane.go
Normal file
14
client/internal/services/core/options/dto/option_pane.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package dto
|
||||
|
||||
import "fyne.io/fyne/v2"
|
||||
|
||||
// OptionPane is a DTO for registering options pane.
|
||||
type OptionPane struct {
|
||||
Widget fyne.CanvasObject
|
||||
SaveHandler OptionSaveHandler
|
||||
Name string
|
||||
}
|
||||
|
||||
// OptionSaveHandler is a signature for functions responsible for saving options, resides in service that registers own
|
||||
// options pane.
|
||||
type OptionSaveHandler func() error
|
17
client/internal/services/core/options/migrations.go
Normal file
17
client/internal/services/core/options/migrations.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//go:embed migrations
|
||||
var migrations embed.FS
|
||||
|
||||
func (o *options) registerMigrations() error {
|
||||
if err := o.db.RegisterMigrations("core/options", migrations); err != nil {
|
||||
return fmt.Errorf("register migrations: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS options (
|
||||
key VARCHAR(1024) NOT NULL UNIQUE,
|
||||
value VARCHAR(8192)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS options;
|
23
client/internal/services/core/options/models/option_pane.go
Normal file
23
client/internal/services/core/options/models/option_pane.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"bunker/client/internal/services/core/options/dto"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
)
|
||||
|
||||
// OptionPane это описание одной панели настроек в окне настроек.
|
||||
type OptionPane struct {
|
||||
Widget fyne.CanvasObject
|
||||
SaveHandler func() error
|
||||
Name string
|
||||
}
|
||||
|
||||
// OptionPaneFromDTO конвертирует параметры панели настроек из DTO во внутреннее представление.
|
||||
func OptionPaneFromDTO(dtoData *dto.OptionPane) *OptionPane {
|
||||
return &OptionPane{
|
||||
Widget: dtoData.Widget,
|
||||
SaveHandler: dtoData.SaveHandler,
|
||||
Name: dtoData.Name,
|
||||
}
|
||||
}
|
88
client/internal/services/core/options/options.go
Normal file
88
client/internal/services/core/options/options.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"bunker/client/internal/application"
|
||||
"bunker/client/internal/services/core"
|
||||
"bunker/client/internal/services/core/options/models"
|
||||
)
|
||||
|
||||
var _ = core.Options(&options{})
|
||||
|
||||
type options struct {
|
||||
app *application.Application
|
||||
db core.Database
|
||||
mainWindow core.MainWindow
|
||||
|
||||
widgets map[string]*models.OptionPane
|
||||
widgetsItems []string // для рисования списка Fyne.
|
||||
}
|
||||
|
||||
// Initialize инициализирует сервис.
|
||||
func Initialize(app *application.Application) error {
|
||||
opts := &options{
|
||||
app: app,
|
||||
}
|
||||
|
||||
if err := app.RegisterService(opts); err != nil {
|
||||
return fmt.Errorf("%w: %w", core.ErrOptions, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *options) Configure() error {
|
||||
if err := o.registerMigrations(); err != nil {
|
||||
return fmt.Errorf("configure: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *options) ConnectDependencies() error {
|
||||
databaseRaw := o.app.Service(core.ServiceNameDatabase)
|
||||
if databaseRaw == nil {
|
||||
return fmt.Errorf("connect dependencies: get database service: %w", application.ErrServiceNotFound)
|
||||
}
|
||||
|
||||
database, valid := databaseRaw.(core.Database)
|
||||
if !valid {
|
||||
return fmt.Errorf("connect dependencies: type assert database service: %w", core.ErrDatabaseIsInvalid)
|
||||
}
|
||||
|
||||
o.db = database
|
||||
|
||||
mainWindowRaw := o.app.Service(core.ServiceNameMainWindow)
|
||||
if mainWindowRaw == nil {
|
||||
return fmt.Errorf("connect dependencies: get main window: %w", application.ErrServiceNotFound)
|
||||
}
|
||||
|
||||
mainWindow, valid := mainWindowRaw.(core.MainWindow)
|
||||
if !valid {
|
||||
return fmt.Errorf("connect dependencies: type assert main window: %w", core.ErrMainWindowIsInvalid)
|
||||
}
|
||||
|
||||
o.mainWindow = mainWindow
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *options) Initialize() error {
|
||||
o.widgets = make(map[string]*models.OptionPane)
|
||||
o.widgetsItems = make([]string, 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *options) Name() string {
|
||||
return core.ServiceNameOptions
|
||||
}
|
||||
|
||||
func (o *options) LaunchStartupTasks() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *options) Shutdown() error {
|
||||
return nil
|
||||
}
|
28
client/internal/services/core/options/widgets.go
Normal file
28
client/internal/services/core/options/widgets.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"bunker/client/internal/services/core"
|
||||
"bunker/client/internal/services/core/options/dto"
|
||||
"bunker/client/internal/services/core/options/models"
|
||||
)
|
||||
|
||||
var errWidgetPaneAlreadyRegistered = errors.New("widget pane already registered")
|
||||
|
||||
func (o *options) RegisterOptionsWidget(widgetData *dto.OptionPane) error {
|
||||
if _, found := o.widgets[widgetData.Name]; found {
|
||||
return fmt.Errorf(
|
||||
"%w: RegisterOptionsWidget: '%s': %w",
|
||||
core.ErrOptions,
|
||||
widgetData.Name,
|
||||
errWidgetPaneAlreadyRegistered,
|
||||
)
|
||||
}
|
||||
|
||||
o.widgets[widgetData.Name] = models.OptionPaneFromDTO(widgetData)
|
||||
o.widgetsItems = append(o.widgetsItems, widgetData.Name)
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user