diff --git a/internal/application/convertor/queue.go b/internal/application/convertor/queue.go index d15beb6..455009c 100644 --- a/internal/application/convertor/queue.go +++ b/internal/application/convertor/queue.go @@ -67,6 +67,7 @@ func NewQueueList() QueueListContract { return &queueList{ currentKey: 0, items: map[int]*Queue{}, + queue: map[int]int{}, queueListener: map[int]QueueListenerContract{}, } } diff --git a/internal/controller/convertor.go b/internal/controller/convertor.go index aae050a..445a32d 100644 --- a/internal/controller/convertor.go +++ b/internal/controller/convertor.go @@ -1,9 +1,12 @@ package controller import ( + "errors" + "fyne.io/fyne/v2/lang" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/download/service" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils" ) func (c *controller) convertor() { @@ -19,6 +22,7 @@ func (c *controller) convertor() { c.app.GetSetting().GetDirectoryForSaving(), c.setDirectoryForSaving, formats, + c.addToConversion, ) c.window.SetContent(content) } @@ -32,6 +36,33 @@ func (c *controller) setDirectoryForSaving(path string) { c.app.GetSetting().SetDirectoryForSaving(path) } +func (c *controller) addToConversion(convertSetting view.ConvertSetting) error { + if len(c.app.GetItemsToConvert().GetItems()) == 0 { + return errors.New(lang.L("errorNoFilesAddedForConversion")) + } + c.window.GetLayout().GetRContainer().SelectFileQueueTab() + for _, item := range c.app.GetItemsToConvert().GetItems() { + file := item.GetFile() + if file == nil { + continue + } + + c.app.GetQueueService().Add(&ffmpeg.ConvertSetting{ + FileInput: *file, + FileOut: ffmpeg.File{ + Path: convertSetting.DirectoryForSave + utils.PathSeparator() + file.Name + "." + convertSetting.Format, + Name: file.Name, + Ext: "." + convertSetting.Format, + }, + OverwriteOutputFiles: convertSetting.OverwriteOutputFiles, + Encoder: convertSetting.Encoder, + }) + } + c.app.GetItemsToConvert().AfterAddingQueue() + + return nil +} + func (c *controller) settingConvertor(isAllowCancellation bool) { ffmpegPath := c.app.GetFFmpegService().GetFFmpegPath() ffprobePath := c.app.GetFFmpegService().GetFFprobePath() diff --git a/internal/controller/main.go b/internal/controller/main.go index db86488..78dff67 100644 --- a/internal/controller/main.go +++ b/internal/controller/main.go @@ -18,7 +18,7 @@ type controller struct { func NewController(app application.AppContract) ControllerContract { fyneWindow := app.FyneApp().NewWindow(app.FyneApp().Metadata().Name) - queueLayout := window.NewQueueLayout() + queueLayout := window.NewQueueLayout(app.GetFFmpegService()) app.GetQueueService().AddListener(queueLayout) return &controller{ diff --git a/internal/ffmpeg/utilities.go b/internal/ffmpeg/utilities.go index 5c7c891..214f862 100644 --- a/internal/ffmpeg/utilities.go +++ b/internal/ffmpeg/utilities.go @@ -14,8 +14,8 @@ type File struct { } type ConvertSetting struct { - VideoFileInput File - VideoFileOut File + FileInput File + FileOut File OverwriteOutputFiles bool Encoder encoder.EncoderContract } diff --git a/internal/gui/view/convertor.go b/internal/gui/view/convertor.go index 7eb722d..cac1bc2 100644 --- a/internal/gui/view/convertor.go +++ b/internal/gui/view/convertor.go @@ -148,19 +148,20 @@ func newFormConvertor( directoryForSavingButton.button.Disable() formConvertor.form.Disable() - err := addToConversion(ConvertSetting{ - DirectoryForSave: directoryForSavingButton.path, - OverwriteOutputFiles: isOverwriteOutputFiles, - Format: selectEncoder.SelectFormat.Selected, - Encoder: selectEncoder.Encoder, + fyne.Do(func() { + err := addToConversion(ConvertSetting{ + DirectoryForSave: directoryForSavingButton.path, + OverwriteOutputFiles: isOverwriteOutputFiles, + Format: selectEncoder.SelectFormat.Selected, + Encoder: selectEncoder.Encoder, + }) + if err != nil { + formConvertor.conversionMessage.Text = err.Error() + } + fileForConversion.button.Enable() + directoryForSavingButton.button.Enable() + formConvertor.form.Enable() }) - if err != nil { - formConvertor.conversionMessage.Text = err.Error() - } - - fileForConversion.button.Enable() - directoryForSavingButton.button.Enable() - formConvertor.form.Enable() } return formConvertor diff --git a/internal/gui/window/queue.go b/internal/gui/window/queue.go index 31be767..9bcb4c0 100644 --- a/internal/gui/window/queue.go +++ b/internal/gui/window/queue.go @@ -4,8 +4,12 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/lang" + "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/convertor" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg" + "image/color" "strconv" "strings" ) @@ -23,15 +27,17 @@ type queueLayout struct { itemsContainer *fyne.Container queueAllStatistics QueueStatisticsAllContract items map[int]queueLayoutItem + ffmpegService ffmpeg.UtilitiesContract } -func NewQueueLayout() QueueLayoutContract { +func NewQueueLayout(ffmpegService ffmpeg.UtilitiesContract) QueueLayoutContract { items := map[int]queueLayoutItem{} return &queueLayout{ itemsContainer: container.NewVBox(), queueAllStatistics: newQueueAllStatistics(&items), items: items, + ffmpegService: ffmpegService, } } @@ -43,16 +49,92 @@ func (l *queueLayout) GetQueueStatistics() QueueStatisticsAllContract { return l.queueAllStatistics } -func (l *queueLayout) AddQueue(key int, queue *convertor.Queue) { +func (l *queueLayout) AddQueue(queueID int, queue *convertor.Queue) { + + statusMessage := canvas.NewText(l.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.FileInput.Name)), + container.NewHBox( + buttonPlay, + statusMessage, + ), + blockMessageError, + container.NewPadded(), + canvas.NewLine(theme.Color(theme.ColorNameFocus)), + container.NewPadded(), + ) + l.addQueueStatistics() + if l.GetQueueStatistics().IsChecked(queue.Status) == false { + content.Hide() + } + + l.items[queueID] = queueLayoutItem{ + CanvasObject: content, + StatusMessage: statusMessage, + BlockMessageError: blockMessageError, + MessageError: messageError, + buttonPlay: buttonPlay, + status: queue.Status, + } + l.itemsContainer.Add(content) } -func (l *queueLayout) ChangeQueue(key int, queue *convertor.Queue) { - l.changeQueueStatistics(queue.Status) +func (l *queueLayout) ChangeQueue(queueID int, queue *convertor.Queue) { + if item, ok := l.items[queueID]; ok { + statusColor := l.getStatusColor(queue.Status) + fyne.Do(func() { + item.StatusMessage.Text = l.getStatusTitle(queue.Status) + item.StatusMessage.Color = statusColor + item.StatusMessage.Refresh() + }) + if queue.Error != nil { + fyne.Do(func() { + item.MessageError.Text = queue.Error.Error() + item.MessageError.Color = statusColor + item.BlockMessageError.Show() + item.MessageError.Refresh() + }) + } + if queue.Status == convertor.StatusType(convertor.Completed) { + item.buttonPlay.Show() + item.buttonPlay.OnTapped = func() { + item.buttonPlay.Disable() + go func() { + ffplay, err := l.ffmpegService.GetFFplay() + if err == nil { + _ = ffplay.Play(&queue.Setting.FileOut) + } + fyne.Do(func() { + item.buttonPlay.Enable() + }) + }() + } + } + if l.GetQueueStatistics().IsChecked(queue.Status) == false && item.CanvasObject.Visible() == true { + item.CanvasObject.Hide() + } else if item.CanvasObject.Visible() == false { + item.CanvasObject.Show() + } + + l.changeQueueStatistics(queue.Status) + } } -func (l *queueLayout) RemoveQueue(key int, status convertor.StatusContract) { - l.removeQueueStatistics(status) +func (l *queueLayout) RemoveQueue(queueID int, status convertor.StatusContract) { + if item, ok := l.items[queueID]; ok { + l.itemsContainer.Remove(item.CanvasObject) + l.removeQueueStatistics(status) + l.items[queueID] = queueLayoutItem{} + } } func (l *queueLayout) addQueueStatistics() { @@ -104,12 +186,30 @@ func (l *queueLayout) removeQueueStatistics(status convertor.StatusContract) { } } +func (l *queueLayout) getStatusTitle(status convertor.StatusContract) string { + return lang.L(status.Name() + "Queue") +} + +func (l *queueLayout) getStatusColor(status convertor.StatusContract) color.Color { + if status == convertor.StatusType(convertor.Error) { + return theme.Color(theme.ColorNameError) + } + + if status == convertor.StatusType(convertor.Completed) { + return color.RGBA{R: 49, G: 127, B: 114, A: 255} + } + + return theme.Color(theme.ColorNamePrimary) +} + type QueueStatisticsAllContract interface { GetWaiting() QueueStatisticsContract GetInProgress() QueueStatisticsContract GetCompleted() QueueStatisticsContract GetError() QueueStatisticsContract GetTotal() QueueStatisticsContract + + IsChecked(status convertor.StatusContract) bool } type queueAllStatistics struct { @@ -203,6 +303,23 @@ func (s *queueAllStatistics) GetTotal() QueueStatisticsContract { return s.total } +func (s *queueAllStatistics) IsChecked(status convertor.StatusContract) bool { + if status == convertor.StatusType(convertor.InProgress) { + return s.inProgress.GetCheckbox().Checked + } + if status == convertor.StatusType(convertor.Completed) { + return s.completed.GetCheckbox().Checked + } + if status == convertor.StatusType(convertor.Error) { + return s.error.GetCheckbox().Checked + } + if status == convertor.StatusType(convertor.Waiting) { + return s.waiting.GetCheckbox().Checked + } + + return true +} + func (s *queueAllStatistics) redrawingQueueItems(queueItems *map[int]queueLayoutItem) { for _, item := range *queueItems { if s.isChecked(item.status) == true && item.CanvasObject.Visible() == false {