Ensure the "Added Files" tab is automatically selected after users drag and drop files for conversion. This improves user experience by guiding them to the newly added content.
540 lines
15 KiB
Go
540 lines
15 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"
|
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
|
"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(&i18n.LocalizeConfig{MessageID: "fileForConversionTitle"}),
|
|
Widget: fileForConversion.button,
|
|
},
|
|
{
|
|
Widget: container.NewHScroll(fileForConversion.message),
|
|
},
|
|
{
|
|
Text: app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{MessageID: "buttonForSelectedDirTitle"}),
|
|
Widget: directoryForSaving.button,
|
|
},
|
|
{
|
|
Widget: container.NewHScroll(directoryForSaving.message),
|
|
},
|
|
{
|
|
Widget: overwriteOutputFiles.checkbox,
|
|
},
|
|
{
|
|
Widget: selectEncoder.SelectFileType,
|
|
},
|
|
{
|
|
Text: app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{MessageID: "selectFormat"}),
|
|
Widget: selectEncoder.SelectFormat,
|
|
},
|
|
{
|
|
Text: app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{MessageID: "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(&i18n.LocalizeConfig{
|
|
MessageID: "errorNoFilesAddedForConversion",
|
|
})))
|
|
c.enableFormConversion()
|
|
return
|
|
}
|
|
|
|
if len(c.directoryForSaving.path) == 0 {
|
|
showConversionMessage(c.conversionMessage, errors.New(c.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
|
MessageID: "errorSelectedFolderSave",
|
|
})))
|
|
c.enableFormConversion()
|
|
return
|
|
}
|
|
if len(c.selectEncoder.SelectFormat.Selected) == 0 {
|
|
showConversionMessage(c.conversionMessage, errors.New(c.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
|
MessageID: "errorSelectedFormat",
|
|
})))
|
|
return
|
|
}
|
|
if c.selectEncoder.Encoder == nil {
|
|
showConversionMessage(c.conversionMessage, errors.New(c.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
|
MessageID: "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(&i18n.LocalizeConfig{
|
|
MessageID: "choose",
|
|
}) + "\n" + app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
|
MessageID: "or",
|
|
}) + "\n" + app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
|
MessageID: "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(&i18n.LocalizeConfig{
|
|
MessageID: "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(&i18n.LocalizeConfig{
|
|
MessageID: "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, err := settingDirectoryForSaving.GetDirectoryForSaving()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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(&i18n.LocalizeConfig{
|
|
MessageID: "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(&i18n.LocalizeConfig{MessageID: "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(&i18n.LocalizeConfig{MessageID: "encoderGroupVideo"})
|
|
encoderGroupAudio := app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{MessageID: "encoderGroupAudio"})
|
|
encoderGroupImage := app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{MessageID: "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(&i18n.LocalizeConfig{
|
|
MessageID: "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()
|
|
}
|