Replaced the `i18n` and `toml` dependencies with Fyne's built-in language system for localization management. Updated the `Localizer` implementation to handle translations using JSON files and embed functionality. Simplified language selection and persisted settings via Fyne's preferences API.
516 lines
14 KiB
Go
516 lines
14 KiB
Go
package view
|
|
|
|
import (
|
|
"errors"
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/storage"
|
|
"fyne.io/fyne/v2/widget"
|
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/convertor/view/form_items"
|
|
encoder2 "git.kor-elf.net/kor-elf/gui-for-ffmpeg/encoder"
|
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel"
|
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel/encoder"
|
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/setting"
|
|
"image/color"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
type ConversionContract interface {
|
|
GetContent() fyne.CanvasObject
|
|
AfterViewContent()
|
|
}
|
|
|
|
type Conversion struct {
|
|
app kernel.AppContract
|
|
form *form
|
|
conversionMessage *canvas.Text
|
|
fileForConversion *fileForConversion
|
|
directoryForSaving *directoryForSaving
|
|
overwriteOutputFiles *overwriteOutputFiles
|
|
selectEncoder *selectEncoder
|
|
runConvert func(setting HandleConvertSetting)
|
|
itemsToConvertService kernel.ItemsToConvertContract
|
|
}
|
|
|
|
type HandleConvertSetting struct {
|
|
DirectoryForSave string
|
|
OverwriteOutputFiles bool
|
|
Format string
|
|
Encoder encoder2.EncoderContract
|
|
}
|
|
|
|
func NewConversion(app kernel.AppContract, formats encoder.ConvertorFormatsContract, runConvert func(setting HandleConvertSetting), settingDirectoryForSaving setting.DirectoryForSavingContract, itemsToConvertService kernel.ItemsToConvertContract) *Conversion {
|
|
conversionMessage := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
|
conversionMessage.TextSize = 16
|
|
conversionMessage.TextStyle = fyne.TextStyle{Bold: true}
|
|
|
|
fileForConversion := newFileForConversion(app, itemsToConvertService)
|
|
directoryForSaving := newDirectoryForSaving(app, settingDirectoryForSaving)
|
|
overwriteOutputFiles := newOverwriteOutputFiles(app)
|
|
selectEncoder := newSelectEncoder(app, formats)
|
|
|
|
items := []*widget.FormItem{
|
|
{
|
|
Text: app.GetLocalizerService().GetMessage("fileForConversionTitle"),
|
|
Widget: fileForConversion.button,
|
|
},
|
|
{
|
|
Widget: container.NewHScroll(fileForConversion.message),
|
|
},
|
|
{
|
|
Text: app.GetLocalizerService().GetMessage("buttonForSelectedDirTitle"),
|
|
Widget: directoryForSaving.button,
|
|
},
|
|
{
|
|
Widget: container.NewHScroll(directoryForSaving.message),
|
|
},
|
|
{
|
|
Widget: overwriteOutputFiles.checkbox,
|
|
},
|
|
{
|
|
Widget: selectEncoder.SelectFileType,
|
|
},
|
|
{
|
|
Text: app.GetLocalizerService().GetMessage("selectFormat"),
|
|
Widget: selectEncoder.SelectFormat,
|
|
},
|
|
{
|
|
Text: app.GetLocalizerService().GetMessage("selectEncoder"),
|
|
Widget: selectEncoder.SelectEncoder,
|
|
},
|
|
}
|
|
form := newForm(app, items)
|
|
|
|
return &Conversion{
|
|
app: app,
|
|
form: form,
|
|
conversionMessage: conversionMessage,
|
|
fileForConversion: fileForConversion,
|
|
directoryForSaving: directoryForSaving,
|
|
overwriteOutputFiles: overwriteOutputFiles,
|
|
selectEncoder: selectEncoder,
|
|
runConvert: runConvert,
|
|
itemsToConvertService: itemsToConvertService,
|
|
}
|
|
}
|
|
|
|
func (c Conversion) GetContent() fyne.CanvasObject {
|
|
c.form.form.OnSubmit = c.submit
|
|
c.fileForConversion.AddChangeCallback(c.selectFileForConversion)
|
|
c.selectEncoder.AddChangeCallback(c.changeEncoder)
|
|
if c.selectEncoder.Encoder != nil {
|
|
c.selectEncoder.SelectEncoder.SetSelectedIndex(c.selectEncoder.SelectEncoder.SelectedIndex())
|
|
}
|
|
|
|
return container.NewVBox(
|
|
c.form.form,
|
|
c.conversionMessage,
|
|
)
|
|
}
|
|
|
|
func (c Conversion) changeEncoder(encoder encoder2.EncoderContract) {
|
|
items := []*widget.FormItem{}
|
|
|
|
if form_items.Views[encoder.GetName()] != nil {
|
|
items = form_items.Views[encoder.GetName()](encoder, c.app)
|
|
}
|
|
|
|
c.form.ChangeItems(items)
|
|
}
|
|
|
|
func (c Conversion) AfterViewContent() {
|
|
if len(c.itemsToConvertService.GetItems()) == 0 {
|
|
c.form.form.Disable()
|
|
}
|
|
}
|
|
|
|
func (c Conversion) selectFileForConversion(err error) {
|
|
c.conversionMessage.Text = ""
|
|
if len(c.itemsToConvertService.GetItems()) == 0 {
|
|
if err != nil {
|
|
c.form.form.Disable()
|
|
return
|
|
}
|
|
}
|
|
|
|
c.form.form.Enable()
|
|
}
|
|
|
|
func (c Conversion) submit() {
|
|
if len(c.itemsToConvertService.GetItems()) == 0 {
|
|
showConversionMessage(c.conversionMessage, errors.New(c.app.GetLocalizerService().GetMessage("errorNoFilesAddedForConversion")))
|
|
c.enableFormConversion()
|
|
return
|
|
}
|
|
|
|
if len(c.directoryForSaving.path) == 0 {
|
|
showConversionMessage(c.conversionMessage, errors.New(c.app.GetLocalizerService().GetMessage("errorSelectedFolderSave")))
|
|
c.enableFormConversion()
|
|
return
|
|
}
|
|
if len(c.selectEncoder.SelectFormat.Selected) == 0 {
|
|
showConversionMessage(c.conversionMessage, errors.New(c.app.GetLocalizerService().GetMessage("errorSelectedFormat")))
|
|
return
|
|
}
|
|
if c.selectEncoder.Encoder == nil {
|
|
showConversionMessage(c.conversionMessage, errors.New(c.app.GetLocalizerService().GetMessage("errorSelectedEncoder")))
|
|
return
|
|
}
|
|
c.conversionMessage.Text = ""
|
|
|
|
c.fileForConversion.button.Disable()
|
|
c.directoryForSaving.button.Disable()
|
|
c.form.form.Disable()
|
|
|
|
c.runConvert(HandleConvertSetting{
|
|
DirectoryForSave: c.directoryForSaving.path,
|
|
OverwriteOutputFiles: c.overwriteOutputFiles.IsChecked(),
|
|
Format: c.selectEncoder.SelectFormat.Selected,
|
|
Encoder: c.selectEncoder.Encoder,
|
|
})
|
|
c.enableFormConversion()
|
|
|
|
if len(c.itemsToConvertService.GetItems()) == 0 {
|
|
c.form.form.Disable()
|
|
}
|
|
}
|
|
|
|
func (c Conversion) enableFormConversion() {
|
|
c.fileForConversion.button.Enable()
|
|
c.directoryForSaving.button.Enable()
|
|
c.form.form.Enable()
|
|
}
|
|
|
|
type fileForConversion struct {
|
|
button *widget.Button
|
|
message *canvas.Text
|
|
file *kernel.File
|
|
|
|
changeCallbacks map[int]func(err error)
|
|
}
|
|
|
|
func newFileForConversion(app kernel.AppContract, itemsToConvertService kernel.ItemsToConvertContract) *fileForConversion {
|
|
message := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
|
fileForConversion := &fileForConversion{
|
|
message: message,
|
|
|
|
changeCallbacks: map[int]func(err error){},
|
|
}
|
|
|
|
buttonTitle := app.GetLocalizerService().GetMessage("choose") + "\n" +
|
|
app.GetLocalizerService().GetMessage("or") + "\n" +
|
|
app.GetLocalizerService().GetMessage("dragAndDropFiles")
|
|
|
|
var locationURI fyne.ListableURI
|
|
|
|
fileForConversion.button = widget.NewButton(buttonTitle, func() {
|
|
app.GetWindow().NewFileOpen(func(r fyne.URIReadCloser, err error) {
|
|
fyne.Do(func() {
|
|
fileForConversion.message.Text = ""
|
|
fileForConversion.message.Refresh()
|
|
})
|
|
|
|
if err != nil {
|
|
fyne.Do(func() {
|
|
fileForConversion.message.Text = err.Error()
|
|
fileForConversion.message.Refresh()
|
|
})
|
|
fileForConversion.eventSelectFile(err)
|
|
return
|
|
}
|
|
if r == nil {
|
|
return
|
|
}
|
|
app.GetWindow().GetLayout().GetRightTabs().SelectAddedFilesTab()
|
|
|
|
itemsToConvertService.Add(&kernel.File{
|
|
Path: r.URI().Path(),
|
|
Name: r.URI().Name(),
|
|
Ext: r.URI().Extension(),
|
|
})
|
|
|
|
fileForConversion.eventSelectFile(nil)
|
|
|
|
listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path()))
|
|
locationURI, _ = storage.ListerForURI(listableURI)
|
|
}, locationURI)
|
|
})
|
|
|
|
app.GetWindow().SetOnDropped(func(position fyne.Position, uris []fyne.URI) {
|
|
if len(uris) == 0 {
|
|
return
|
|
}
|
|
|
|
isError := false
|
|
for _, uri := range uris {
|
|
info, err := os.Stat(uri.Path())
|
|
if err != nil {
|
|
isError = true
|
|
continue
|
|
}
|
|
if info.IsDir() {
|
|
isError = true
|
|
continue
|
|
}
|
|
|
|
itemsToConvertService.Add(&kernel.File{
|
|
Path: uri.Path(),
|
|
Name: uri.Name(),
|
|
Ext: uri.Extension(),
|
|
})
|
|
|
|
fileForConversion.eventSelectFile(nil)
|
|
|
|
listableURI := storage.NewFileURI(filepath.Dir(uri.Path()))
|
|
locationURI, _ = storage.ListerForURI(listableURI)
|
|
}
|
|
app.GetWindow().GetLayout().GetRightTabs().SelectAddedFilesTab()
|
|
if isError {
|
|
fileForConversion.message.Text = app.GetLocalizerService().GetMessage("errorDragAndDropFile")
|
|
setStringErrorStyle(fileForConversion.message)
|
|
fileForConversion.eventSelectFile(errors.New(fileForConversion.message.Text))
|
|
} else {
|
|
fyne.Do(func() {
|
|
fileForConversion.message.Text = ""
|
|
fileForConversion.message.Refresh()
|
|
})
|
|
}
|
|
})
|
|
|
|
return fileForConversion
|
|
}
|
|
|
|
func (c fileForConversion) AddChangeCallback(callback func(err error)) {
|
|
c.changeCallbacks[len(c.changeCallbacks)] = callback
|
|
}
|
|
|
|
func (c fileForConversion) eventSelectFile(err error) {
|
|
for _, changeCallback := range c.changeCallbacks {
|
|
changeCallback(err)
|
|
}
|
|
}
|
|
|
|
type directoryForSaving struct {
|
|
button *widget.Button
|
|
message *canvas.Text
|
|
path string
|
|
}
|
|
|
|
func newDirectoryForSaving(app kernel.AppContract, settingDirectoryForSaving setting.DirectoryForSavingContract) *directoryForSaving {
|
|
directoryForSaving := &directoryForSaving{
|
|
path: "",
|
|
}
|
|
|
|
directoryForSaving.message = canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
|
directoryForSaving.message.TextSize = 16
|
|
directoryForSaving.message.TextStyle = fyne.TextStyle{Bold: true}
|
|
|
|
buttonTitle := app.GetLocalizerService().GetMessage("choose")
|
|
|
|
var locationURI fyne.ListableURI
|
|
|
|
location, err := getDirectoryForSaving(settingDirectoryForSaving)
|
|
if err == nil {
|
|
directoryForSaving.path = location.Path()
|
|
directoryForSaving.message.Text = location.Path()
|
|
setStringSuccessStyle(directoryForSaving.message)
|
|
}
|
|
|
|
directoryForSaving.button = widget.NewButton(buttonTitle, func() {
|
|
app.GetWindow().NewFolderOpen(func(r fyne.ListableURI, err error) {
|
|
if err != nil {
|
|
directoryForSaving.message.Text = err.Error()
|
|
setStringErrorStyle(directoryForSaving.message)
|
|
return
|
|
}
|
|
if r == nil {
|
|
return
|
|
}
|
|
|
|
directoryForSaving.path = r.Path()
|
|
|
|
directoryForSaving.message.Text = r.Path()
|
|
setStringSuccessStyle(directoryForSaving.message)
|
|
locationURI, err = storage.ListerForURI(r)
|
|
|
|
if err == nil {
|
|
_ = settingDirectoryForSaving.SaveDirectoryForSaving(locationURI.Path())
|
|
}
|
|
|
|
}, locationURI)
|
|
})
|
|
|
|
return directoryForSaving
|
|
}
|
|
|
|
func getDirectoryForSaving(settingDirectoryForSaving setting.DirectoryForSavingContract) (fyne.ListableURI, error) {
|
|
path := settingDirectoryForSaving.GetDirectoryForSaving()
|
|
|
|
if len(path) > 0 {
|
|
path = "file://" + path
|
|
}
|
|
|
|
uri, err := storage.ParseURI(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return storage.ListerForURI(uri)
|
|
}
|
|
|
|
type overwriteOutputFiles struct {
|
|
checkbox *widget.Check
|
|
isChecked bool
|
|
}
|
|
|
|
func newOverwriteOutputFiles(app kernel.AppContract) *overwriteOutputFiles {
|
|
overwriteOutputFiles := &overwriteOutputFiles{
|
|
isChecked: false,
|
|
}
|
|
checkboxOverwriteOutputFilesTitle := app.GetLocalizerService().GetMessage("checkboxOverwriteOutputFilesTitle")
|
|
overwriteOutputFiles.checkbox = widget.NewCheck(checkboxOverwriteOutputFilesTitle, func(b bool) {
|
|
overwriteOutputFiles.isChecked = b
|
|
})
|
|
|
|
return overwriteOutputFiles
|
|
}
|
|
|
|
func (receiver overwriteOutputFiles) IsChecked() bool {
|
|
return receiver.isChecked
|
|
}
|
|
|
|
type selectEncoder struct {
|
|
SelectFileType *widget.RadioGroup
|
|
SelectFormat *widget.Select
|
|
SelectEncoder *widget.Select
|
|
Encoder encoder2.EncoderContract
|
|
|
|
changeCallbacks map[int]func(encoder encoder2.EncoderContract)
|
|
}
|
|
|
|
func newSelectEncoder(app kernel.AppContract, formats encoder.ConvertorFormatsContract) *selectEncoder {
|
|
selectEncoder := &selectEncoder{
|
|
changeCallbacks: map[int]func(encoder encoder2.EncoderContract){},
|
|
}
|
|
|
|
encoders := map[int]encoder2.EncoderDataContract{}
|
|
selectEncoder.SelectEncoder = widget.NewSelect([]string{}, func(s string) {
|
|
if encoders[selectEncoder.SelectEncoder.SelectedIndex()] == nil {
|
|
return
|
|
}
|
|
selectEncoderData := encoders[selectEncoder.SelectEncoder.SelectedIndex()]
|
|
selectEncoder.ChangeEncoder(selectEncoderData.NewEncoder())
|
|
})
|
|
|
|
formatSelected := ""
|
|
selectEncoder.SelectFormat = widget.NewSelect([]string{}, func(s string) {
|
|
if formatSelected == s {
|
|
return
|
|
}
|
|
formatSelected = s
|
|
format, err := formats.GetFormat(s)
|
|
if err != nil {
|
|
return
|
|
}
|
|
encoderOptions := []string{}
|
|
encoders = map[int]encoder2.EncoderDataContract{}
|
|
for _, e := range format.GetEncoders() {
|
|
encoders[len(encoders)] = e
|
|
encoderOptions = append(encoderOptions, app.GetLocalizerService().GetMessage("encoder_"+e.GetTitle()))
|
|
}
|
|
selectEncoder.SelectEncoder.SetOptions(encoderOptions)
|
|
selectEncoder.SelectEncoder.SetSelectedIndex(0)
|
|
})
|
|
|
|
fileTypeOptions := []string{}
|
|
for _, fileType := range encoder2.GetListFileType() {
|
|
fileTypeOptions = append(fileTypeOptions, fileType.Name())
|
|
}
|
|
|
|
encoderGroupVideo := app.GetLocalizerService().GetMessage("encoderGroupVideo")
|
|
encoderGroupAudio := app.GetLocalizerService().GetMessage("encoderGroupAudio")
|
|
encoderGroupImage := app.GetLocalizerService().GetMessage("encoderGroupImage")
|
|
encoderGroup := map[string]string{
|
|
encoderGroupVideo: "video",
|
|
encoderGroupAudio: "audio",
|
|
encoderGroupImage: "image",
|
|
}
|
|
selectEncoder.SelectFileType = widget.NewRadioGroup([]string{encoderGroupVideo, encoderGroupAudio, encoderGroupImage}, func(s string) {
|
|
groupCode := encoderGroup[s]
|
|
|
|
formatOptions := []string{}
|
|
for _, f := range formats.GetFormats() {
|
|
if groupCode != f.GetFileType().Name() {
|
|
continue
|
|
}
|
|
formatOptions = append(formatOptions, f.GetTitle())
|
|
}
|
|
selectEncoder.SelectFormat.SetOptions(formatOptions)
|
|
if groupCode == encoder2.FileType(encoder2.Video).Name() {
|
|
selectEncoder.SelectFormat.SetSelected("mp4")
|
|
} else {
|
|
selectEncoder.SelectFormat.SetSelectedIndex(0)
|
|
}
|
|
})
|
|
selectEncoder.SelectFileType.Horizontal = true
|
|
selectEncoder.SelectFileType.Required = true
|
|
selectEncoder.SelectFileType.SetSelected(encoderGroupVideo)
|
|
|
|
return selectEncoder
|
|
}
|
|
|
|
func (e *selectEncoder) ChangeEncoder(encoder encoder2.EncoderContract) {
|
|
e.Encoder = encoder
|
|
e.eventSelectEncoder(e.Encoder)
|
|
}
|
|
|
|
func (e *selectEncoder) AddChangeCallback(callback func(encoder encoder2.EncoderContract)) {
|
|
e.changeCallbacks[len(e.changeCallbacks)] = callback
|
|
}
|
|
|
|
func (e *selectEncoder) eventSelectEncoder(encoder encoder2.EncoderContract) {
|
|
for _, changeCallback := range e.changeCallbacks {
|
|
changeCallback(encoder)
|
|
}
|
|
}
|
|
|
|
func setStringErrorStyle(text *canvas.Text) {
|
|
text.Color = color.RGBA{R: 255, G: 0, B: 0, A: 255}
|
|
text.Refresh()
|
|
}
|
|
|
|
func setStringSuccessStyle(text *canvas.Text) {
|
|
text.Color = color.RGBA{R: 49, G: 127, B: 114, A: 255}
|
|
text.Refresh()
|
|
}
|
|
|
|
func showConversionMessage(conversionMessage *canvas.Text, err error) {
|
|
conversionMessage.Text = err.Error()
|
|
setStringErrorStyle(conversionMessage)
|
|
}
|
|
|
|
type form struct {
|
|
form *widget.Form
|
|
items []*widget.FormItem
|
|
}
|
|
|
|
func newForm(app kernel.AppContract, items []*widget.FormItem) *form {
|
|
f := widget.NewForm()
|
|
f.SubmitText = app.GetLocalizerService().GetMessage("converterVideoFilesSubmitTitle")
|
|
f.Items = items
|
|
|
|
return &form{
|
|
form: f,
|
|
items: items,
|
|
}
|
|
}
|
|
|
|
func (f form) ChangeItems(items []*widget.FormItem) {
|
|
f.form.Items = f.items
|
|
f.form.Refresh()
|
|
f.form.Items = append(f.form.Items, items...)
|
|
f.form.Refresh()
|
|
}
|