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:
@@ -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)
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user