Make it possible to drag and drop multiple files
It is now possible to add multiple files before sending them to the processing queue.
This commit is contained in:
parent
82167f042f
commit
84b36dd29e
@ -24,30 +24,30 @@ type ConversionContract interface {
|
||||
}
|
||||
|
||||
type Conversion struct {
|
||||
app kernel.AppContract
|
||||
form *form
|
||||
conversionMessage *canvas.Text
|
||||
fileForConversion *fileForConversion
|
||||
directoryForSaving *directoryForSaving
|
||||
overwriteOutputFiles *overwriteOutputFiles
|
||||
selectEncoder *selectEncoder
|
||||
runConvert func(setting HandleConvertSetting)
|
||||
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 {
|
||||
FileInput kernel.File
|
||||
DirectoryForSave string
|
||||
OverwriteOutputFiles bool
|
||||
Format string
|
||||
Encoder encoder2.EncoderContract
|
||||
}
|
||||
|
||||
func NewConversion(app kernel.AppContract, formats encoder.ConvertorFormatsContract, runConvert func(setting HandleConvertSetting), settingDirectoryForSaving setting.DirectoryForSavingContract) *Conversion {
|
||||
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)
|
||||
fileForConversion := newFileForConversion(app, itemsToConvertService)
|
||||
directoryForSaving := newDirectoryForSaving(app, settingDirectoryForSaving)
|
||||
overwriteOutputFiles := newOverwriteOutputFiles(app)
|
||||
selectEncoder := newSelectEncoder(app, formats)
|
||||
@ -85,14 +85,15 @@ func NewConversion(app kernel.AppContract, formats encoder.ConvertorFormatsContr
|
||||
form := newForm(app, items)
|
||||
|
||||
return &Conversion{
|
||||
app: app,
|
||||
form: form,
|
||||
conversionMessage: conversionMessage,
|
||||
fileForConversion: fileForConversion,
|
||||
directoryForSaving: directoryForSaving,
|
||||
overwriteOutputFiles: overwriteOutputFiles,
|
||||
selectEncoder: selectEncoder,
|
||||
runConvert: runConvert,
|
||||
app: app,
|
||||
form: form,
|
||||
conversionMessage: conversionMessage,
|
||||
fileForConversion: fileForConversion,
|
||||
directoryForSaving: directoryForSaving,
|
||||
overwriteOutputFiles: overwriteOutputFiles,
|
||||
selectEncoder: selectEncoder,
|
||||
runConvert: runConvert,
|
||||
itemsToConvertService: itemsToConvertService,
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,20 +122,32 @@ func (c Conversion) changeEncoder(encoder encoder2.EncoderContract) {
|
||||
}
|
||||
|
||||
func (c Conversion) AfterViewContent() {
|
||||
c.form.form.Disable()
|
||||
if len(c.itemsToConvertService.GetItems()) == 0 {
|
||||
c.form.form.Disable()
|
||||
}
|
||||
}
|
||||
|
||||
func (c Conversion) selectFileForConversion(err error) {
|
||||
c.conversionMessage.Text = ""
|
||||
if err != nil {
|
||||
c.form.form.Disable()
|
||||
return
|
||||
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",
|
||||
@ -160,18 +173,17 @@ func (c Conversion) submit() {
|
||||
c.directoryForSaving.button.Disable()
|
||||
c.form.form.Disable()
|
||||
|
||||
setting := HandleConvertSetting{
|
||||
FileInput: *c.fileForConversion.file,
|
||||
c.runConvert(HandleConvertSetting{
|
||||
DirectoryForSave: c.directoryForSaving.path,
|
||||
OverwriteOutputFiles: c.overwriteOutputFiles.IsChecked(),
|
||||
Format: c.selectEncoder.SelectFormat.Selected,
|
||||
Encoder: c.selectEncoder.Encoder,
|
||||
}
|
||||
c.runConvert(setting)
|
||||
})
|
||||
c.enableFormConversion()
|
||||
|
||||
c.fileForConversion.message.Text = ""
|
||||
c.form.form.Disable()
|
||||
if len(c.itemsToConvertService.GetItems()) == 0 {
|
||||
c.form.form.Disable()
|
||||
}
|
||||
}
|
||||
|
||||
func (c Conversion) enableFormConversion() {
|
||||
@ -188,44 +200,49 @@ type fileForConversion struct {
|
||||
changeCallbacks map[int]func(err error)
|
||||
}
|
||||
|
||||
func newFileForConversion(app kernel.AppContract) *fileForConversion {
|
||||
func newFileForConversion(app kernel.AppContract, itemsToConvertService kernel.ItemsToConvertContract) *fileForConversion {
|
||||
message := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||
fileForConversion := &fileForConversion{
|
||||
file: &kernel.File{},
|
||||
message: message,
|
||||
|
||||
changeCallbacks: map[int]func(err error){},
|
||||
}
|
||||
|
||||
buttonTitle := app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "choose",
|
||||
}) + "\n\r\n\r" + app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
||||
}) + "\n" + app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "or",
|
||||
}) + "\n\r\n\r" + app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "dragAndDrop1File",
|
||||
}) + "\n" + app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "dragAndDropFiles",
|
||||
})
|
||||
|
||||
fileForConversion.message = canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||
fileForConversion.message.TextSize = 16
|
||||
fileForConversion.message.TextStyle = fyne.TextStyle{Bold: true}
|
||||
|
||||
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 {
|
||||
fileForConversion.message.Text = err.Error()
|
||||
setStringErrorStyle(fileForConversion.message)
|
||||
fyne.Do(func() {
|
||||
fileForConversion.message.Text = err.Error()
|
||||
fileForConversion.message.Refresh()
|
||||
})
|
||||
fileForConversion.eventSelectFile(err)
|
||||
return
|
||||
}
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
app.GetWindow().GetLayout().GetRightTabs().SelectAddedFilesTab()
|
||||
|
||||
fileForConversion.file.Path = r.URI().Path()
|
||||
fileForConversion.file.Name = r.URI().Name()
|
||||
fileForConversion.file.Ext = r.URI().Extension()
|
||||
|
||||
fileForConversion.message.Text = r.URI().Path()
|
||||
setStringSuccessStyle(fileForConversion.message)
|
||||
itemsToConvertService.Add(&kernel.File{
|
||||
Path: r.URI().Path(),
|
||||
Name: r.URI().Name(),
|
||||
Ext: r.URI().Extension(),
|
||||
})
|
||||
|
||||
fileForConversion.eventSelectFile(nil)
|
||||
|
||||
@ -239,43 +256,41 @@ func newFileForConversion(app kernel.AppContract) *fileForConversion {
|
||||
return
|
||||
}
|
||||
|
||||
if len(uris) > 1 {
|
||||
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)
|
||||
}
|
||||
if isError {
|
||||
fileForConversion.message.Text = app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "errorDragAndDrop1File",
|
||||
MessageID: "errorDragAndDropFile",
|
||||
})
|
||||
setStringErrorStyle(fileForConversion.message)
|
||||
fileForConversion.eventSelectFile(errors.New(fileForConversion.message.Text))
|
||||
return
|
||||
}
|
||||
|
||||
uri := uris[0]
|
||||
info, err := os.Stat(uri.Path())
|
||||
if err != nil {
|
||||
fileForConversion.message.Text = err.Error()
|
||||
setStringErrorStyle(fileForConversion.message)
|
||||
fileForConversion.eventSelectFile(err)
|
||||
return
|
||||
}
|
||||
if info.IsDir() {
|
||||
fileForConversion.message.Text = app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "errorIsFolder",
|
||||
} else {
|
||||
fyne.Do(func() {
|
||||
fileForConversion.message.Text = ""
|
||||
fileForConversion.message.Refresh()
|
||||
})
|
||||
setStringErrorStyle(fileForConversion.message)
|
||||
fileForConversion.eventSelectFile(errors.New(fileForConversion.message.Text))
|
||||
return
|
||||
}
|
||||
|
||||
fileForConversion.file.Path = uri.Path()
|
||||
fileForConversion.file.Name = uri.Name()
|
||||
fileForConversion.file.Ext = uri.Extension()
|
||||
|
||||
fileForConversion.message.Text = uri.Path()
|
||||
setStringSuccessStyle(fileForConversion.message)
|
||||
|
||||
fileForConversion.eventSelectFile(nil)
|
||||
|
||||
listableURI := storage.NewFileURI(filepath.Dir(uri.Path()))
|
||||
locationURI, _ = storage.ListerForURI(listableURI)
|
||||
})
|
||||
|
||||
return fileForConversion
|
||||
|
@ -25,6 +25,7 @@ type ConvertorHandler struct {
|
||||
errorView error2.ViewContract
|
||||
convertorRepository convertor.RepositoryContract
|
||||
settingDirectoryForSaving setting.DirectoryForSavingContract
|
||||
itemsToConvertService kernel.ItemsToConvertContract
|
||||
}
|
||||
|
||||
func NewConvertorHandler(
|
||||
@ -33,6 +34,7 @@ func NewConvertorHandler(
|
||||
errorView error2.ViewContract,
|
||||
convertorRepository convertor.RepositoryContract,
|
||||
settingDirectoryForSaving setting.DirectoryForSavingContract,
|
||||
itemsToConvertService kernel.ItemsToConvertContract,
|
||||
) *ConvertorHandler {
|
||||
return &ConvertorHandler{
|
||||
app: app,
|
||||
@ -40,6 +42,7 @@ func NewConvertorHandler(
|
||||
errorView: errorView,
|
||||
convertorRepository: convertorRepository,
|
||||
settingDirectoryForSaving: settingDirectoryForSaving,
|
||||
itemsToConvertService: itemsToConvertService,
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +53,7 @@ func (h ConvertorHandler) MainConvertor() {
|
||||
h.errorView.PanicError(err)
|
||||
return
|
||||
}
|
||||
conversion := view.NewConversion(h.app, formats, h.runConvert, h.settingDirectoryForSaving)
|
||||
conversion := view.NewConversion(h.app, formats, h.runConvert, h.settingDirectoryForSaving, h.itemsToConvertService)
|
||||
h.convertorView.Main(conversion)
|
||||
return
|
||||
}
|
||||
@ -77,16 +80,26 @@ func (h ConvertorHandler) GetFfplayVersion() (string, error) {
|
||||
}
|
||||
|
||||
func (h ConvertorHandler) runConvert(setting view.HandleConvertSetting) {
|
||||
h.app.GetQueue().Add(&kernel.ConvertSetting{
|
||||
VideoFileInput: setting.FileInput,
|
||||
VideoFileOut: kernel.File{
|
||||
Path: setting.DirectoryForSave + helper.PathSeparator() + setting.FileInput.Name + "." + setting.Format,
|
||||
Name: setting.FileInput.Name,
|
||||
Ext: "." + setting.Format,
|
||||
},
|
||||
OverwriteOutputFiles: setting.OverwriteOutputFiles,
|
||||
Encoder: setting.Encoder,
|
||||
})
|
||||
h.app.GetWindow().GetLayout().GetRightTabs().SelectFileQueueTab()
|
||||
|
||||
for _, item := range h.itemsToConvertService.GetItems() {
|
||||
file := item.GetFile()
|
||||
if file == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
h.app.GetQueue().Add(&kernel.ConvertSetting{
|
||||
VideoFileInput: *file,
|
||||
VideoFileOut: kernel.File{
|
||||
Path: setting.DirectoryForSave + helper.PathSeparator() + file.Name + "." + setting.Format,
|
||||
Name: file.Name,
|
||||
Ext: "." + setting.Format,
|
||||
},
|
||||
OverwriteOutputFiles: setting.OverwriteOutputFiles,
|
||||
Encoder: setting.Encoder,
|
||||
})
|
||||
}
|
||||
h.itemsToConvertService.AfterAddingQueue()
|
||||
}
|
||||
|
||||
func (h ConvertorHandler) checkingFFPathUtilities() bool {
|
||||
|
@ -12,6 +12,7 @@ type AppContract interface {
|
||||
GetQueue() QueueListContract
|
||||
GetLocalizerService() LocalizerContract
|
||||
GetConvertorService() ConvertorContract
|
||||
GetFFplayService() FFplayContract
|
||||
AfterClosing()
|
||||
RunConvertor()
|
||||
}
|
||||
@ -21,27 +22,36 @@ type App struct {
|
||||
Window WindowContract
|
||||
Queue QueueListContract
|
||||
|
||||
localizerService LocalizerContract
|
||||
convertorService ConvertorContract
|
||||
localizerService LocalizerContract
|
||||
convertorService ConvertorContract
|
||||
blockProgressbarService BlockProgressbarContract
|
||||
ffplayService FFplayContract
|
||||
}
|
||||
|
||||
func NewApp(
|
||||
metadata *fyne.AppMetadata,
|
||||
localizerService LocalizerContract,
|
||||
queue QueueListContract,
|
||||
queueLayoutObject QueueLayoutObjectContract,
|
||||
ffplayService FFplayContract,
|
||||
convertorService ConvertorContract,
|
||||
) *App {
|
||||
app.SetMetadata(*metadata)
|
||||
a := app.New()
|
||||
|
||||
statusesText := GetBlockProgressbarStatusesText(localizerService)
|
||||
blockProgressbarService := NewBlockProgressbar(statusesText, ffplayService)
|
||||
rightTabsService := NewRightTabs(localizerService)
|
||||
queueLayoutObject := NewQueueLayoutObject(queue, localizerService, ffplayService, rightTabsService, blockProgressbarService.GetContainer())
|
||||
|
||||
return &App{
|
||||
AppFyne: a,
|
||||
Window: newWindow(a.NewWindow("GUI for FFmpeg"), NewLayout(queueLayoutObject, localizerService)),
|
||||
Window: newWindow(a.NewWindow("GUI for FFmpeg"), NewLayout(queueLayoutObject, localizerService, rightTabsService)),
|
||||
Queue: queue,
|
||||
|
||||
localizerService: localizerService,
|
||||
convertorService: convertorService,
|
||||
localizerService: localizerService,
|
||||
convertorService: convertorService,
|
||||
blockProgressbarService: blockProgressbarService,
|
||||
ffplayService: ffplayService,
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,6 +75,10 @@ func (a App) GetConvertorService() ConvertorContract {
|
||||
return a.convertorService
|
||||
}
|
||||
|
||||
func (a App) GetFFplayService() FFplayContract {
|
||||
return a.ffplayService
|
||||
}
|
||||
|
||||
func (a App) AfterClosing() {
|
||||
for _, cmd := range a.convertorService.GetRunningProcesses() {
|
||||
_ = cmd.Process.Kill()
|
||||
@ -81,22 +95,33 @@ func (a App) RunConvertor() {
|
||||
}
|
||||
queue.Status = StatusType(InProgress)
|
||||
a.Window.GetLayout().ChangeQueueStatus(queueId, queue)
|
||||
if a.blockProgressbarService.GetContainer().Hidden {
|
||||
a.blockProgressbarService.GetContainer().Show()
|
||||
}
|
||||
|
||||
totalDuration, err := a.convertorService.GetTotalDuration(&queue.Setting.VideoFileInput)
|
||||
if err != nil {
|
||||
totalDuration = 0
|
||||
}
|
||||
progress := a.Window.GetLayout().NewProgressbar(queueId, totalDuration)
|
||||
|
||||
progress := a.blockProgressbarService.GetProgressbar(
|
||||
totalDuration,
|
||||
queue.Setting.VideoFileInput.Path,
|
||||
a.localizerService,
|
||||
)
|
||||
|
||||
err = a.convertorService.RunConvert(*queue.Setting, progress)
|
||||
if err != nil {
|
||||
queue.Status = StatusType(Error)
|
||||
queue.Error = err
|
||||
a.Window.GetLayout().ChangeQueueStatus(queueId, queue)
|
||||
a.blockProgressbarService.ProcessEndedWithError(err.Error())
|
||||
|
||||
continue
|
||||
}
|
||||
queue.Status = StatusType(Completed)
|
||||
a.Window.GetLayout().ChangeQueueStatus(queueId, queue)
|
||||
a.blockProgressbarService.ProcessEndedWithSuccess(queue.Setting.VideoFileOut.Path)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
151
kernel/items_to_convert.go
Normal file
151
kernel/items_to_convert.go
Normal file
@ -0,0 +1,151 @@
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
)
|
||||
|
||||
type ItemsToConvertContract interface {
|
||||
Add(file *File)
|
||||
GetItems() map[int]ItemToConvertContract
|
||||
AfterAddingQueue()
|
||||
}
|
||||
|
||||
type ItemsToConvert struct {
|
||||
nextId int
|
||||
items map[int]ItemToConvertContract
|
||||
itemsContainer *fyne.Container
|
||||
ffplayService FFplayContract
|
||||
isAutoRemove bool
|
||||
}
|
||||
|
||||
func NewItemsToConvert(itemsContainer *fyne.Container, ffplayService FFplayContract, localizerService LocalizerContract) *ItemsToConvert {
|
||||
containerForItems := container.NewVBox()
|
||||
ItemsToConvert := &ItemsToConvert{
|
||||
nextId: 0,
|
||||
items: map[int]ItemToConvertContract{},
|
||||
itemsContainer: containerForItems,
|
||||
ffplayService: ffplayService,
|
||||
isAutoRemove: true,
|
||||
}
|
||||
|
||||
line := canvas.NewLine(theme.Color(theme.ColorNameFocus))
|
||||
line.StrokeWidth = 5
|
||||
checkboxAutoRemove := widget.NewCheck(localizerService.GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "autoClearAfterAddingToQueue",
|
||||
}), func(checked bool) {
|
||||
ItemsToConvert.isAutoRemove = checked
|
||||
})
|
||||
checkboxAutoRemove.SetChecked(ItemsToConvert.isAutoRemove)
|
||||
localizerService.AddChangeCallback("autoClearAfterAddingToQueue", func(text string) {
|
||||
checkboxAutoRemove.Text = text
|
||||
})
|
||||
|
||||
buttonClear := widget.NewButton(localizerService.GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "clearAll",
|
||||
}), func() {
|
||||
ItemsToConvert.clear()
|
||||
})
|
||||
buttonClear.Importance = widget.DangerImportance
|
||||
localizerService.AddChangeCallback("clearAll", func(text string) {
|
||||
buttonClear.Text = text
|
||||
})
|
||||
|
||||
itemsContainer.Add(container.NewVBox(
|
||||
container.NewPadded(),
|
||||
container.NewBorder(nil, nil, nil, buttonClear, container.NewHScroll(checkboxAutoRemove)),
|
||||
container.NewPadded(),
|
||||
line,
|
||||
container.NewPadded(),
|
||||
containerForItems,
|
||||
))
|
||||
|
||||
return ItemsToConvert
|
||||
}
|
||||
|
||||
func (items *ItemsToConvert) Add(file *File) {
|
||||
nextId := items.nextId
|
||||
var content *fyne.Container
|
||||
var buttonPlay *widget.Button
|
||||
|
||||
buttonPlay = widget.NewButtonWithIcon("", theme.Icon(theme.IconNameMediaPlay), func() {
|
||||
buttonPlay.Disable()
|
||||
go func() {
|
||||
_ = items.ffplayService.Run(FFplaySetting{
|
||||
PathToFile: file.Path,
|
||||
})
|
||||
fyne.Do(func() {
|
||||
buttonPlay.Enable()
|
||||
})
|
||||
}()
|
||||
})
|
||||
|
||||
buttonRemove := widget.NewButtonWithIcon("", theme.Icon(theme.IconNameDelete), func() {
|
||||
items.itemsContainer.Remove(content)
|
||||
items.itemsContainer.Refresh()
|
||||
delete(items.items, nextId)
|
||||
})
|
||||
buttonRemove.Importance = widget.DangerImportance
|
||||
|
||||
content = container.NewVBox(
|
||||
container.NewBorder(
|
||||
nil,
|
||||
nil,
|
||||
buttonPlay,
|
||||
buttonRemove,
|
||||
container.NewHScroll(widget.NewLabel(file.Name)),
|
||||
),
|
||||
container.NewHScroll(widget.NewLabel(file.Path)),
|
||||
container.NewPadded(),
|
||||
canvas.NewLine(theme.Color(theme.ColorNameFocus)),
|
||||
container.NewPadded(),
|
||||
)
|
||||
|
||||
items.itemsContainer.Add(content)
|
||||
items.items[nextId] = NewItemToConvert(file, content)
|
||||
items.nextId++
|
||||
}
|
||||
|
||||
func (items *ItemsToConvert) GetItems() map[int]ItemToConvertContract {
|
||||
return items.items
|
||||
}
|
||||
|
||||
func (items *ItemsToConvert) AfterAddingQueue() {
|
||||
if items.isAutoRemove {
|
||||
items.clear()
|
||||
}
|
||||
}
|
||||
|
||||
func (items *ItemsToConvert) clear() {
|
||||
items.itemsContainer.RemoveAll()
|
||||
items.items = map[int]ItemToConvertContract{}
|
||||
}
|
||||
|
||||
type ItemToConvertContract interface {
|
||||
GetFile() *File
|
||||
GetContent() *fyne.Container
|
||||
}
|
||||
|
||||
type ItemToConvert struct {
|
||||
file *File
|
||||
content *fyne.Container
|
||||
}
|
||||
|
||||
func NewItemToConvert(file *File, content *fyne.Container) *ItemToConvert {
|
||||
return &ItemToConvert{
|
||||
file: file,
|
||||
content: content,
|
||||
}
|
||||
}
|
||||
|
||||
func (item ItemToConvert) GetFile() *File {
|
||||
return item.file
|
||||
}
|
||||
|
||||
func (item ItemToConvert) GetContent() *fyne.Container {
|
||||
return item.content
|
||||
}
|
185
kernel/layout.go
185
kernel/layout.go
@ -1,8 +1,6 @@
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/container"
|
||||
@ -10,31 +8,31 @@ import (
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"image/color"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type LayoutContract interface {
|
||||
SetContent(content fyne.CanvasObject) *fyne.Container
|
||||
NewProgressbar(queueId int, totalDuration float64) ProgressContract
|
||||
ChangeQueueStatus(queueId int, queue *Queue)
|
||||
GetRightTabs() RightTabsContract
|
||||
}
|
||||
|
||||
type Layout struct {
|
||||
layout *fyne.Container
|
||||
queueLayoutObject QueueLayoutObjectContract
|
||||
localizerService LocalizerContract
|
||||
rightTabsService RightTabsContract
|
||||
}
|
||||
|
||||
func NewLayout(queueLayoutObject QueueLayoutObjectContract, localizerService LocalizerContract) *Layout {
|
||||
layout := container.NewAdaptiveGrid(2, widget.NewLabel(""), container.NewVScroll(queueLayoutObject.GetCanvasObject()))
|
||||
func NewLayout(queueLayoutObject QueueLayoutObjectContract, localizerService LocalizerContract, rightTabsService RightTabsContract) *Layout {
|
||||
layout := container.NewAdaptiveGrid(2, widget.NewLabel(""), queueLayoutObject.GetCanvasObject())
|
||||
|
||||
return &Layout{
|
||||
layout: layout,
|
||||
queueLayoutObject: queueLayoutObject,
|
||||
localizerService: localizerService,
|
||||
rightTabsService: rightTabsService,
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,18 +41,16 @@ func (l Layout) SetContent(content fyne.CanvasObject) *fyne.Container {
|
||||
return l.layout
|
||||
}
|
||||
|
||||
func (l Layout) NewProgressbar(queueId int, totalDuration float64) ProgressContract {
|
||||
progressbar := l.queueLayoutObject.GetProgressbar(queueId)
|
||||
return NewProgress(totalDuration, progressbar, l.localizerService)
|
||||
}
|
||||
|
||||
func (l Layout) ChangeQueueStatus(queueId int, queue *Queue) {
|
||||
l.queueLayoutObject.ChangeQueueStatus(queueId, queue)
|
||||
}
|
||||
|
||||
func (l Layout) GetRightTabs() RightTabsContract {
|
||||
return l.rightTabsService
|
||||
}
|
||||
|
||||
type QueueLayoutObjectContract interface {
|
||||
GetCanvasObject() fyne.CanvasObject
|
||||
GetProgressbar(queueId int) *widget.ProgressBar
|
||||
ChangeQueueStatus(queueId int, queue *Queue)
|
||||
}
|
||||
|
||||
@ -63,6 +59,7 @@ type QueueLayoutObject struct {
|
||||
|
||||
queue QueueListContract
|
||||
container *fyne.Container
|
||||
containerItems *fyne.Container
|
||||
items map[int]QueueLayoutItem
|
||||
localizerService LocalizerContract
|
||||
queueStatisticsFormat *queueStatisticsFormat
|
||||
@ -70,16 +67,16 @@ type QueueLayoutObject struct {
|
||||
}
|
||||
|
||||
type QueueLayoutItem struct {
|
||||
CanvasObject fyne.CanvasObject
|
||||
ProgressBar *widget.ProgressBar
|
||||
StatusMessage *canvas.Text
|
||||
MessageError *canvas.Text
|
||||
buttonPlay *widget.Button
|
||||
CanvasObject fyne.CanvasObject
|
||||
BlockMessageError *container.Scroll
|
||||
StatusMessage *canvas.Text
|
||||
MessageError *canvas.Text
|
||||
buttonPlay *widget.Button
|
||||
|
||||
status *StatusContract
|
||||
}
|
||||
|
||||
func NewQueueLayoutObject(queue QueueListContract, localizerService LocalizerContract, ffplayService FFplayContract) *QueueLayoutObject {
|
||||
func NewQueueLayoutObject(queue QueueListContract, localizerService LocalizerContract, ffplayService FFplayContract, rightTabsService RightTabsContract, blockProgressbar *fyne.Container) *QueueLayoutObject {
|
||||
title := widget.NewLabel(localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "queue"}))
|
||||
title.TextStyle.Bold = true
|
||||
|
||||
@ -91,12 +88,27 @@ func NewQueueLayoutObject(queue QueueListContract, localizerService LocalizerCon
|
||||
items := map[int]QueueLayoutItem{}
|
||||
queueStatisticsFormat := newQueueStatisticsFormat(localizerService, &items)
|
||||
|
||||
line := canvas.NewLine(theme.Color(theme.ColorNameFocus))
|
||||
line.StrokeWidth = 5
|
||||
|
||||
rightTabsService.GetFileQueueContainer().Add(container.NewVBox(
|
||||
container.NewPadded(),
|
||||
container.NewHBox(title, queueStatisticsFormat.completed.widget, queueStatisticsFormat.error.widget),
|
||||
container.NewHBox(queueStatisticsFormat.inProgress.widget, queueStatisticsFormat.waiting.widget, queueStatisticsFormat.total.widget),
|
||||
container.NewPadded(),
|
||||
line,
|
||||
container.NewPadded(),
|
||||
))
|
||||
queueLayoutObject := &QueueLayoutObject{
|
||||
queue: queue,
|
||||
container: container.NewVBox(
|
||||
container.NewHBox(title, queueStatisticsFormat.completed.widget, queueStatisticsFormat.error.widget),
|
||||
container.NewHBox(queueStatisticsFormat.inProgress.widget, queueStatisticsFormat.waiting.widget, queueStatisticsFormat.total.widget),
|
||||
container: container.NewBorder(
|
||||
container.NewVBox(
|
||||
blockProgressbar,
|
||||
widget.NewSeparator(),
|
||||
),
|
||||
nil, nil, nil, container.NewVScroll(rightTabsService.GetTabs()),
|
||||
),
|
||||
containerItems: rightTabsService.GetFileQueueContainer(),
|
||||
items: items,
|
||||
localizerService: localizerService,
|
||||
queueStatisticsFormat: queueStatisticsFormat,
|
||||
@ -112,31 +124,24 @@ func (o QueueLayoutObject) GetCanvasObject() fyne.CanvasObject {
|
||||
return o.container
|
||||
}
|
||||
|
||||
func (o QueueLayoutObject) GetProgressbar(queueId int) *widget.ProgressBar {
|
||||
if item, ok := o.items[queueId]; ok {
|
||||
return item.ProgressBar
|
||||
}
|
||||
return widget.NewProgressBar()
|
||||
}
|
||||
|
||||
func (o QueueLayoutObject) Add(id int, queue *Queue) {
|
||||
progressBar := widget.NewProgressBar()
|
||||
|
||||
statusMessage := canvas.NewText(o.getStatusTitle(queue.Status), theme.Color(theme.ColorNamePrimary))
|
||||
messageError := canvas.NewText("", theme.Color(theme.ColorNameError))
|
||||
buttonPlay := widget.NewButtonWithIcon("", theme.Icon(theme.IconNameMediaPlay), func() {
|
||||
|
||||
})
|
||||
buttonPlay.Hide()
|
||||
blockMessageError := container.NewHScroll(messageError)
|
||||
blockMessageError.Hide()
|
||||
|
||||
content := container.NewVBox(
|
||||
container.NewHScroll(widget.NewLabel(queue.Setting.VideoFileInput.Name)),
|
||||
progressBar,
|
||||
container.NewHScroll(container.NewHBox(
|
||||
container.NewHBox(
|
||||
buttonPlay,
|
||||
statusMessage,
|
||||
)),
|
||||
container.NewHScroll(messageError),
|
||||
),
|
||||
blockMessageError,
|
||||
container.NewPadded(),
|
||||
canvas.NewLine(theme.Color(theme.ColorNameFocus)),
|
||||
container.NewPadded(),
|
||||
)
|
||||
@ -147,14 +152,14 @@ func (o QueueLayoutObject) Add(id int, queue *Queue) {
|
||||
}
|
||||
|
||||
o.items[id] = QueueLayoutItem{
|
||||
CanvasObject: content,
|
||||
ProgressBar: progressBar,
|
||||
StatusMessage: statusMessage,
|
||||
MessageError: messageError,
|
||||
buttonPlay: buttonPlay,
|
||||
status: &queue.Status,
|
||||
CanvasObject: content,
|
||||
StatusMessage: statusMessage,
|
||||
BlockMessageError: blockMessageError,
|
||||
MessageError: messageError,
|
||||
buttonPlay: buttonPlay,
|
||||
status: &queue.Status,
|
||||
}
|
||||
o.container.Add(content)
|
||||
o.containerItems.Add(content)
|
||||
}
|
||||
|
||||
func (o QueueLayoutObject) Remove(id int) {
|
||||
@ -177,6 +182,7 @@ func (o QueueLayoutObject) ChangeQueueStatus(queueId int, queue *Queue) {
|
||||
item.MessageError.Text = queue.Error.Error()
|
||||
item.MessageError.Color = statusColor
|
||||
fyne.Do(func() {
|
||||
item.BlockMessageError.Show()
|
||||
item.MessageError.Refresh()
|
||||
})
|
||||
}
|
||||
@ -219,101 +225,6 @@ func (o QueueLayoutObject) getStatusTitle(status StatusContract) string {
|
||||
return o.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: status.Name() + "Queue"})
|
||||
}
|
||||
|
||||
type Progress struct {
|
||||
totalDuration float64
|
||||
progressbar *widget.ProgressBar
|
||||
protocol string
|
||||
localizerService LocalizerContract
|
||||
}
|
||||
|
||||
func NewProgress(totalDuration float64, progressbar *widget.ProgressBar, localizerService LocalizerContract) Progress {
|
||||
return Progress{
|
||||
totalDuration: totalDuration,
|
||||
progressbar: progressbar,
|
||||
protocol: "pipe:",
|
||||
localizerService: localizerService,
|
||||
}
|
||||
}
|
||||
|
||||
func (p Progress) GetProtocole() string {
|
||||
return p.protocol
|
||||
}
|
||||
|
||||
func (p Progress) Run(stdOut io.ReadCloser, stdErr io.ReadCloser) error {
|
||||
isProcessCompleted := false
|
||||
var errorText string
|
||||
|
||||
p.progressbar.Value = 0
|
||||
p.progressbar.Max = p.totalDuration
|
||||
fyne.Do(func() {
|
||||
p.progressbar.Refresh()
|
||||
})
|
||||
progress := 0.0
|
||||
|
||||
go func() {
|
||||
scannerErr := bufio.NewReader(stdErr)
|
||||
for {
|
||||
line, _, err := scannerErr.ReadLine()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
data := strings.TrimSpace(string(line))
|
||||
errorText = data
|
||||
}
|
||||
}()
|
||||
|
||||
scannerOut := bufio.NewReader(stdOut)
|
||||
for {
|
||||
line, _, err := scannerOut.ReadLine()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
data := strings.TrimSpace(string(line))
|
||||
if strings.Contains(data, "progress=end") {
|
||||
p.progressbar.Value = p.totalDuration
|
||||
fyne.Do(func() {
|
||||
p.progressbar.Refresh()
|
||||
})
|
||||
isProcessCompleted = true
|
||||
break
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`frame=(\d+)`)
|
||||
a := re.FindAllStringSubmatch(data, -1)
|
||||
|
||||
if len(a) > 0 && len(a[len(a)-1]) > 0 {
|
||||
c, err := strconv.Atoi(a[len(a)-1][len(a[len(a)-1])-1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
progress = float64(c)
|
||||
}
|
||||
if p.progressbar.Value != progress {
|
||||
p.progressbar.Value = progress
|
||||
fyne.Do(func() {
|
||||
p.progressbar.Refresh()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if isProcessCompleted == false {
|
||||
if len(errorText) == 0 {
|
||||
errorText = p.localizerService.GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "errorConverter",
|
||||
})
|
||||
}
|
||||
return errors.New(errorText)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type queueStatistics struct {
|
||||
widget *widget.Check
|
||||
title string
|
||||
|
254
kernel/progressbar.go
Normal file
254
kernel/progressbar.go
Normal file
@ -0,0 +1,254 @@
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"image/color"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type BlockProgressbarContract interface {
|
||||
GetContainer() *fyne.Container
|
||||
GetProgressbar(totalDuration float64, filePath string, localizerService LocalizerContract) Progress
|
||||
ProcessEndedWithError(errorText string)
|
||||
ProcessEndedWithSuccess(filePath string)
|
||||
}
|
||||
|
||||
type BlockProgressbar struct {
|
||||
container *fyne.Container
|
||||
label *widget.Label
|
||||
progressbar *widget.ProgressBar
|
||||
errorBlock *container.Scroll
|
||||
messageError *canvas.Text
|
||||
statusMessage *canvas.Text
|
||||
buttonPlay *widget.Button
|
||||
statusesText *BlockProgressbarStatusesText
|
||||
ffplayService FFplayContract
|
||||
}
|
||||
|
||||
func NewBlockProgressbar(statusesText *BlockProgressbarStatusesText, ffplayService FFplayContract) *BlockProgressbar {
|
||||
label := widget.NewLabel("")
|
||||
progressbar := widget.NewProgressBar()
|
||||
|
||||
statusMessage := canvas.NewText("", theme.Color(theme.ColorNamePrimary))
|
||||
messageError := canvas.NewText("", theme.Color(theme.ColorNameError))
|
||||
buttonPlay := widget.NewButtonWithIcon("", theme.Icon(theme.IconNameMediaPlay), func() {
|
||||
|
||||
})
|
||||
buttonPlay.Hide()
|
||||
|
||||
errorBlock := container.NewHScroll(messageError)
|
||||
errorBlock.Hide()
|
||||
|
||||
content := container.NewVBox(
|
||||
container.NewHScroll(label),
|
||||
progressbar,
|
||||
container.NewHScroll(container.NewHBox(
|
||||
buttonPlay,
|
||||
statusMessage,
|
||||
)),
|
||||
errorBlock,
|
||||
)
|
||||
content.Hide()
|
||||
|
||||
return &BlockProgressbar{
|
||||
container: content,
|
||||
label: label,
|
||||
progressbar: progressbar,
|
||||
errorBlock: errorBlock,
|
||||
messageError: messageError,
|
||||
statusMessage: statusMessage,
|
||||
buttonPlay: buttonPlay,
|
||||
statusesText: statusesText,
|
||||
ffplayService: ffplayService,
|
||||
}
|
||||
}
|
||||
|
||||
func (block BlockProgressbar) GetContainer() *fyne.Container {
|
||||
return block.container
|
||||
}
|
||||
|
||||
func (block BlockProgressbar) GetProgressbar(totalDuration float64, filePath string, localizerService LocalizerContract) Progress {
|
||||
block.label.Text = filePath
|
||||
block.statusMessage.Color = theme.Color(theme.ColorNamePrimary)
|
||||
block.statusMessage.Text = block.statusesText.inProgress
|
||||
block.messageError.Text = ""
|
||||
fyne.Do(func() {
|
||||
block.buttonPlay.Hide()
|
||||
if block.errorBlock.Visible() {
|
||||
block.errorBlock.Hide()
|
||||
}
|
||||
block.statusMessage.Refresh()
|
||||
block.container.Refresh()
|
||||
block.errorBlock.Refresh()
|
||||
})
|
||||
|
||||
block.progressbar.Value = 0
|
||||
return NewProgress(totalDuration, block.progressbar, localizerService)
|
||||
}
|
||||
|
||||
func (block BlockProgressbar) ProcessEndedWithError(errorText string) {
|
||||
fyne.Do(func() {
|
||||
block.statusMessage.Color = theme.Color(theme.ColorNameError)
|
||||
block.statusMessage.Text = block.statusesText.error
|
||||
block.messageError.Text = errorText
|
||||
block.errorBlock.Show()
|
||||
})
|
||||
}
|
||||
|
||||
func (block BlockProgressbar) ProcessEndedWithSuccess(filePath string) {
|
||||
fyne.Do(func() {
|
||||
block.statusMessage.Color = color.RGBA{R: 49, G: 127, B: 114, A: 255}
|
||||
block.statusMessage.Text = block.statusesText.completed
|
||||
block.buttonPlay.Show()
|
||||
block.buttonPlay.OnTapped = func() {
|
||||
block.buttonPlay.Disable()
|
||||
go func() {
|
||||
_ = block.ffplayService.Run(FFplaySetting{
|
||||
PathToFile: filePath,
|
||||
})
|
||||
fyne.Do(func() {
|
||||
block.buttonPlay.Enable()
|
||||
})
|
||||
}()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type Progress struct {
|
||||
totalDuration float64
|
||||
progressbar *widget.ProgressBar
|
||||
protocol string
|
||||
localizerService LocalizerContract
|
||||
}
|
||||
|
||||
func NewProgress(totalDuration float64, progressbar *widget.ProgressBar, localizerService LocalizerContract) Progress {
|
||||
return Progress{
|
||||
totalDuration: totalDuration,
|
||||
progressbar: progressbar,
|
||||
protocol: "pipe:",
|
||||
localizerService: localizerService,
|
||||
}
|
||||
}
|
||||
|
||||
func (p Progress) GetProtocole() string {
|
||||
return p.protocol
|
||||
}
|
||||
|
||||
func (p Progress) Run(stdOut io.ReadCloser, stdErr io.ReadCloser) error {
|
||||
isProcessCompleted := false
|
||||
var errorText string
|
||||
|
||||
p.progressbar.Value = 0
|
||||
p.progressbar.Max = p.totalDuration
|
||||
fyne.Do(func() {
|
||||
p.progressbar.Refresh()
|
||||
})
|
||||
progress := 0.0
|
||||
|
||||
go func() {
|
||||
scannerErr := bufio.NewReader(stdErr)
|
||||
for {
|
||||
line, _, err := scannerErr.ReadLine()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
data := strings.TrimSpace(string(line))
|
||||
errorText = data
|
||||
}
|
||||
}()
|
||||
|
||||
scannerOut := bufio.NewReader(stdOut)
|
||||
for {
|
||||
line, _, err := scannerOut.ReadLine()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
data := strings.TrimSpace(string(line))
|
||||
if strings.Contains(data, "progress=end") {
|
||||
p.progressbar.Value = p.totalDuration
|
||||
fyne.Do(func() {
|
||||
p.progressbar.Refresh()
|
||||
})
|
||||
isProcessCompleted = true
|
||||
break
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`frame=(\d+)`)
|
||||
a := re.FindAllStringSubmatch(data, -1)
|
||||
|
||||
if len(a) > 0 && len(a[len(a)-1]) > 0 {
|
||||
c, err := strconv.Atoi(a[len(a)-1][len(a[len(a)-1])-1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
progress = float64(c)
|
||||
}
|
||||
if p.progressbar.Value != progress {
|
||||
p.progressbar.Value = progress
|
||||
fyne.Do(func() {
|
||||
p.progressbar.Refresh()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if isProcessCompleted == false {
|
||||
if len(errorText) == 0 {
|
||||
errorText = p.localizerService.GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "errorConverter",
|
||||
})
|
||||
}
|
||||
return errors.New(errorText)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type BlockProgressbarStatusesText struct {
|
||||
inProgress string
|
||||
completed string
|
||||
error string
|
||||
}
|
||||
|
||||
func GetBlockProgressbarStatusesText(localizerService LocalizerContract) *BlockProgressbarStatusesText {
|
||||
statusesText := &BlockProgressbarStatusesText{
|
||||
inProgress: localizerService.GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "inProgressQueue",
|
||||
}),
|
||||
completed: localizerService.GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "completedQueue",
|
||||
}),
|
||||
error: localizerService.GetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: "errorQueue",
|
||||
}),
|
||||
}
|
||||
|
||||
localizerService.AddChangeCallback("inProgressQueue", func(text string) {
|
||||
statusesText.inProgress = text
|
||||
})
|
||||
|
||||
localizerService.AddChangeCallback("completedQueue", func(text string) {
|
||||
statusesText.completed = text
|
||||
})
|
||||
|
||||
localizerService.AddChangeCallback("errorQueue", func(text string) {
|
||||
statusesText.error = text
|
||||
})
|
||||
|
||||
return statusesText
|
||||
}
|
76
kernel/right_tabs.go
Normal file
76
kernel/right_tabs.go
Normal file
@ -0,0 +1,76 @@
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
)
|
||||
|
||||
type RightTabsContract interface {
|
||||
GetTabs() *container.AppTabs
|
||||
GetAddedFilesContainer() *fyne.Container
|
||||
GetFileQueueContainer() *fyne.Container
|
||||
SelectFileQueueTab()
|
||||
SelectAddedFilesTab()
|
||||
}
|
||||
|
||||
type RightTabs struct {
|
||||
tabs *container.AppTabs
|
||||
|
||||
addedFilesContainer *fyne.Container
|
||||
addedFilesTab *container.TabItem
|
||||
|
||||
fileQueueContainer *fyne.Container
|
||||
fileQueueTab *container.TabItem
|
||||
}
|
||||
|
||||
func NewRightTabs(localizerService LocalizerContract) *RightTabs {
|
||||
addedFilesContainer := container.NewVBox()
|
||||
addedFilesTab := container.NewTabItem(localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "addedFilesTitle"}), addedFilesContainer)
|
||||
localizerService.AddChangeCallback("addedFilesTitle", func(text string) {
|
||||
addedFilesTab.Text = text
|
||||
})
|
||||
|
||||
fileQueueContainer := container.NewVBox()
|
||||
fileQueueTab := container.NewTabItem(localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "fileQueueTitle"}), fileQueueContainer)
|
||||
localizerService.AddChangeCallback("fileQueueTitle", func(text string) {
|
||||
fileQueueTab.Text = text
|
||||
})
|
||||
|
||||
tabs := container.NewAppTabs(
|
||||
addedFilesTab,
|
||||
fileQueueTab,
|
||||
)
|
||||
|
||||
return &RightTabs{
|
||||
tabs: tabs,
|
||||
addedFilesContainer: addedFilesContainer,
|
||||
addedFilesTab: addedFilesTab,
|
||||
fileQueueContainer: fileQueueContainer,
|
||||
fileQueueTab: fileQueueTab,
|
||||
}
|
||||
}
|
||||
|
||||
func (t RightTabs) GetTabs() *container.AppTabs {
|
||||
return t.tabs
|
||||
}
|
||||
|
||||
func (t RightTabs) GetAddedFilesContainer() *fyne.Container {
|
||||
return t.addedFilesContainer
|
||||
}
|
||||
|
||||
func (t RightTabs) GetFileQueueContainer() *fyne.Container {
|
||||
return t.fileQueueContainer
|
||||
}
|
||||
|
||||
func (t RightTabs) SelectFileQueueTab() {
|
||||
fyne.Do(func() {
|
||||
t.tabs.Select(t.fileQueueTab)
|
||||
})
|
||||
}
|
||||
|
||||
func (t RightTabs) SelectAddedFilesTab() {
|
||||
fyne.Do(func() {
|
||||
t.tabs.Select(t.addedFilesTab)
|
||||
})
|
||||
}
|
@ -10,6 +10,14 @@ other = "About"
|
||||
hash = "sha1-8bd565814118ba8b90c40eb5b62acf8d2676e7d6"
|
||||
other = "A simple interface for the FFmpeg console utility. \nBut I am not the author of the FFmpeg utility itself."
|
||||
|
||||
[addedFilesTitle]
|
||||
hash = "sha1-8ba0f6e477b0d78df2cc06f1d8b41b888623b851"
|
||||
other = "Added files"
|
||||
|
||||
[autoClearAfterAddingToQueue]
|
||||
hash = "sha1-b3781695a4c35380d2cd075bb52f27a2a6d8f19c"
|
||||
other = "Auto-clear after adding to queue"
|
||||
|
||||
[buttonDownloadFFmpeg]
|
||||
hash = "sha1-c223c2e15171156192bc3146aee91e6094bb475b"
|
||||
other = "Download FFmpeg automatically"
|
||||
@ -38,6 +46,10 @@ other = "Allow file to be overwritten"
|
||||
hash = "sha1-f60bb5f761024d973834b5e9d25ceebce2c85f94"
|
||||
other = "choose"
|
||||
|
||||
[clearAll]
|
||||
hash = "sha1-f32702d79ac206432400ac6b041695d020f6fa77"
|
||||
other = "Clear List"
|
||||
|
||||
[completedQueue]
|
||||
hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe"
|
||||
other = "Completed"
|
||||
@ -62,9 +74,9 @@ other = "Will be downloaded from the site:"
|
||||
hash = "sha1-55f87f114628fa2d5d8e67d1e1cda22c0e4f9271"
|
||||
other = "Downloading..."
|
||||
|
||||
[dragAndDrop1File]
|
||||
hash = "sha1-7259670822df1cc92ef5f06ed3c0e9407746975a"
|
||||
other = "drag and drop 1 file"
|
||||
[dragAndDropFiles]
|
||||
hash = "sha1-07bb747cc7590d7a51cdf96dff49a74139097766"
|
||||
other = "drag and drop files"
|
||||
|
||||
[encoderGroupAudio]
|
||||
hash = "sha1-24321cb5400df96be8f3e2131918bebdb3a01bba"
|
||||
@ -226,9 +238,9 @@ other = "could not create file 'database' in folder 'data'"
|
||||
hash = "sha1-f8153516ac2442d19be4b6daccce839d204ff09f"
|
||||
other = "Could not open configuration file.\nMake sure another copy of the program is not running!"
|
||||
|
||||
[errorDragAndDrop1File]
|
||||
hash = "sha1-a8edb5cbd622f3ce4ec07a2377e22ec5fad4491b"
|
||||
other = "You can only drag and drop 1 file."
|
||||
[errorDragAndDropFile]
|
||||
hash = "sha1-863cf1ad9c820d5b0c2006ceeaa29e25f81c1714"
|
||||
other = "Not all files were added"
|
||||
|
||||
[errorFFmpeg]
|
||||
hash = "sha1-ccf0b95c0d1b392dc215258d917eb4e5d0b88ed0"
|
||||
@ -254,9 +266,9 @@ other = "this is not FFprobe"
|
||||
hash = "sha1-da7b37d7df3fafbd153665b13888413d52b24c17"
|
||||
other = "Failed to determine FFprobe version"
|
||||
|
||||
[errorIsFolder]
|
||||
hash = "sha1-f937d090b6e320957514d850657cdf2f911dc6aa"
|
||||
other = "You can only drag and drop a file"
|
||||
[errorNoFilesAddedForConversion]
|
||||
hash = "sha1-5cf1f65bef15cb0382e56be98f44c6abde56a314"
|
||||
other = "There are no files to convert"
|
||||
|
||||
[errorQueue]
|
||||
hash = "sha1-72aecd9ad85642d84d62dbbf3cf70953c5f696c7"
|
||||
@ -290,6 +302,10 @@ other = "**FFmpeg** is a trademark of **[Fabrice Bellard](http://bellard.org/)**
|
||||
hash = "sha1-96ac799e1086b31fd8f5f8d4c801829d6c853f08"
|
||||
other = "File:"
|
||||
|
||||
[fileQueueTitle]
|
||||
hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8"
|
||||
other = "Queue"
|
||||
|
||||
[formPreset]
|
||||
hash = "sha1-7759891ba1ef9f7adc70defc7ac18fbf149c1a68"
|
||||
other = "Preset"
|
||||
|
@ -10,6 +10,14 @@ other = "Бағдарлама туралы"
|
||||
hash = "sha1-8bd565814118ba8b90c40eb5b62acf8d2676e7d6"
|
||||
other = "FFmpeg консоль утилитасы үшін қарапайым интерфейс. \nБірақ мен FFmpeg утилитасының авторы емеспін."
|
||||
|
||||
[addedFilesTitle]
|
||||
hash = "sha1-8ba0f6e477b0d78df2cc06f1d8b41b888623b851"
|
||||
other = "Қосылған файлдар"
|
||||
|
||||
[autoClearAfterAddingToQueue]
|
||||
hash = "sha1-b3781695a4c35380d2cd075bb52f27a2a6d8f19c"
|
||||
other = "Кезекке қосқаннан кейін тазалаңыз"
|
||||
|
||||
[buttonDownloadFFmpeg]
|
||||
hash = "sha1-c223c2e15171156192bc3146aee91e6094bb475b"
|
||||
other = "FFmpeg автоматты түрде жүктеп алыңыз"
|
||||
@ -38,6 +46,10 @@ other = "Файлды қайта жазуға рұқсат беріңіз"
|
||||
hash = "sha1-f60bb5f761024d973834b5e9d25ceebce2c85f94"
|
||||
other = "таңдау"
|
||||
|
||||
[clearAll]
|
||||
hash = "sha1-f32702d79ac206432400ac6b041695d020f6fa77"
|
||||
other = "Тізімді өшіру"
|
||||
|
||||
[completedQueue]
|
||||
hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe"
|
||||
other = "Дайын"
|
||||
@ -62,9 +74,9 @@ other = "Сайттан жүктеледі:"
|
||||
hash = "sha1-55f87f114628fa2d5d8e67d1e1cda22c0e4f9271"
|
||||
other = "Жүктеп алынуда..."
|
||||
|
||||
[dragAndDrop1File]
|
||||
hash = "sha1-7259670822df1cc92ef5f06ed3c0e9407746975a"
|
||||
other = "1 файлды сүйреңіз"
|
||||
[dragAndDropFiles]
|
||||
hash = "sha1-07bb747cc7590d7a51cdf96dff49a74139097766"
|
||||
other = "файлдарды сүйреп апарыңыз"
|
||||
|
||||
[encoderGroupAudio]
|
||||
hash = "sha1-24321cb5400df96be8f3e2131918bebdb3a01bba"
|
||||
@ -226,9 +238,9 @@ other = "'data' қалтасында 'database' файлын жасау мүмк
|
||||
hash = "sha1-f8153516ac2442d19be4b6daccce839d204ff09f"
|
||||
other = "Конфигурация файлын аша алмады.\nБағдарламаның басқа көшірмесі іске қосылмағанына көз жеткізіңіз!"
|
||||
|
||||
[errorDragAndDrop1File]
|
||||
hash = "sha1-a8edb5cbd622f3ce4ec07a2377e22ec5fad4491b"
|
||||
other = "Тек 1 файлды сүйреп апаруға болады"
|
||||
[errorDragAndDropFile]
|
||||
hash = "sha1-863cf1ad9c820d5b0c2006ceeaa29e25f81c1714"
|
||||
other = "Барлық файлдар қосылмаған"
|
||||
|
||||
[errorFFmpeg]
|
||||
hash = "sha1-ccf0b95c0d1b392dc215258d917eb4e5d0b88ed0"
|
||||
@ -254,9 +266,9 @@ other = "бұл FFprobe емес"
|
||||
hash = "sha1-da7b37d7df3fafbd153665b13888413d52b24c17"
|
||||
other = "FFprobe нұсқасын анықтау мүмкін болмады"
|
||||
|
||||
[errorIsFolder]
|
||||
hash = "sha1-f937d090b6e320957514d850657cdf2f911dc6aa"
|
||||
other = "Тек файлды сүйреп апаруға болады"
|
||||
[errorNoFilesAddedForConversion]
|
||||
hash = "sha1-5cf1f65bef15cb0382e56be98f44c6abde56a314"
|
||||
other = "Түрлендіруге арналған файлдар жоқ"
|
||||
|
||||
[errorQueue]
|
||||
hash = "sha1-72aecd9ad85642d84d62dbbf3cf70953c5f696c7"
|
||||
@ -290,6 +302,10 @@ other = "FFmpeg — **[FFmpeg](https://ffmpeg.org/about.html)** жобасын
|
||||
hash = "sha1-96ac799e1086b31fd8f5f8d4c801829d6c853f08"
|
||||
other = "Файл:"
|
||||
|
||||
[fileQueueTitle]
|
||||
hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8"
|
||||
other = "Кезек"
|
||||
|
||||
[formPreset]
|
||||
hash = "sha1-7759891ba1ef9f7adc70defc7ac18fbf149c1a68"
|
||||
other = "Алдын ала орнатылған"
|
||||
|
@ -1,6 +1,8 @@
|
||||
AlsoUsedProgram = "Также в программе используется:"
|
||||
about = "О программе"
|
||||
aboutText = "Простенький интерфейс для консольной утилиты FFmpeg. \nНо я не являюсь автором самой утилиты FFmpeg."
|
||||
addedFilesTitle = "Добавленные файлы"
|
||||
autoClearAfterAddingToQueue = "Очищать после добавления в очередь"
|
||||
buttonDownloadFFmpeg = "Скачать автоматически FFmpeg"
|
||||
buttonForSelectedDirTitle = "Сохранить в папку:"
|
||||
cancel = "Отмена"
|
||||
@ -8,13 +10,14 @@ changeFFPath = "FFmpeg, FFprobe и FFplay"
|
||||
changeLanguage = "Поменять язык"
|
||||
checkboxOverwriteOutputFilesTitle = "Разрешить перезаписать файл"
|
||||
choose = "выбрать"
|
||||
clearAll = "Очистить список"
|
||||
completedQueue = "Готово"
|
||||
converterVideoFilesSubmitTitle = "Конвертировать"
|
||||
converterVideoFilesTitle = "Конвертер видео, аудио и картинок"
|
||||
download = "Скачать"
|
||||
downloadFFmpegFromSite = "Будет скачано с сайта:"
|
||||
downloadRun = "Скачивается..."
|
||||
dragAndDrop1File = "перетащить 1 файл"
|
||||
dragAndDropFiles = "перетащить файлы"
|
||||
encoderGroupAudio = "Аудио"
|
||||
encoderGroupImage = "Картинки"
|
||||
encoderGroupVideo = "Видео"
|
||||
@ -55,14 +58,14 @@ error = "Произошла ошибка!"
|
||||
errorConverter = "не смогли отконвертировать видео"
|
||||
errorDatabase = "не смогли создать файл 'database' в папке 'data'"
|
||||
errorDatabaseTimeout = "Не смогли открыть файл конфигурации.\nУбедитесь, что другая копия программы не запущена!"
|
||||
errorDragAndDrop1File = "Можно перетащить только 1 файл"
|
||||
errorDragAndDropFile = "Не все файлы добавились"
|
||||
errorFFmpeg = "это не FFmpeg"
|
||||
errorFFmpegVersion = "Не смогли определить версию FFmpeg"
|
||||
errorFFplay = "это не FFplay"
|
||||
errorFFplayVersion = "Не смогли определить версию FFplay"
|
||||
errorFFprobe = "это не FFprobe"
|
||||
errorFFprobeVersion = "Не смогли определить версию FFprobe"
|
||||
errorIsFolder = "Можно перетаскивать только файл"
|
||||
errorNoFilesAddedForConversion = "Нет файлов для конвертации"
|
||||
errorQueue = "Ошибка"
|
||||
errorSelectedEncoder = "Конвертер не выбран"
|
||||
errorSelectedFolderSave = "Папка для сохранения не выбрана!"
|
||||
@ -71,6 +74,7 @@ exit = "Выход"
|
||||
ffmpegLGPL = "Это программное обеспечение использует библиотеки из проекта **FFmpeg** под **[LGPLv2.1](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html)**."
|
||||
ffmpegTrademark = "**FFmpeg** — торговая марка **[Fabrice Bellard](http://bellard.org/)** , создателя проекта **[FFmpeg](https://ffmpeg.org/about.html)**."
|
||||
fileForConversionTitle = "Файл:"
|
||||
fileQueueTitle = "Очередь"
|
||||
formPreset = "Предустановка"
|
||||
gratitude = "Благодарность"
|
||||
gratitudeText = "Я искренне благодарю вас за неоценимую\n\rи своевременную помощь:"
|
||||
|
9
main.go
9
main.go
@ -46,7 +46,7 @@ func init() {
|
||||
appMetadata,
|
||||
localizerService,
|
||||
queue,
|
||||
kernel.NewQueueLayoutObject(queue, localizerService, ffplayService),
|
||||
ffplayService,
|
||||
convertorService,
|
||||
)
|
||||
}
|
||||
@ -108,7 +108,12 @@ func main() {
|
||||
|
||||
localizerView := localizer.NewView(application)
|
||||
convertorView := convertor.NewView(application)
|
||||
convertorHandler := handler.NewConvertorHandler(application, convertorView, errorView, convertorRepository, settingDirectoryForSaving)
|
||||
itemsToConvertService := kernel.NewItemsToConvert(
|
||||
application.GetWindow().GetLayout().GetRightTabs().GetAddedFilesContainer(),
|
||||
application.GetFFplayService(),
|
||||
application.GetLocalizerService(),
|
||||
)
|
||||
convertorHandler := handler.NewConvertorHandler(application, convertorView, errorView, convertorRepository, settingDirectoryForSaving, itemsToConvertService)
|
||||
|
||||
themeRepository := theme.NewRepository(settingRepository)
|
||||
themeService := theme.NewTheme(application, themeRepository)
|
||||
|
Loading…
x
Reference in New Issue
Block a user